/*****************************************************************************************/ /* David Cheung Phillip Wang Mau-En Lee Wei Yuan ENEE429 Spring 1999 FM 5/16/99 For the TI TMS320C541. This program implements FM for AMPS. The AIC samples a message and stores these samples into an input buffer. Once a frame has been sampled, the program generates I and Q values of the samples. The program then performs demodulation on these I and Q values, storing the demodulated signal in the output buffer for transmission through the AIC. FSK, straight AIC echo, and AIC echo with notch filter have also been implemented. Please assign the macro COMPILE_TYPE with the desired program function and re-compile before running this program. NOTE: AR1,6,7 are automatically preserved ONLY in C function calls!!!! Do not use AR1,6,7 as global variables! C function calls may alter these registers. */ /*****************************************************************************************/ #include #include #include #include "aic_01c.h" #include "c54xregs.h" #include "main.h" /* header file for this main.c */ #include "notch.h" /*****************************************************************************************/ /* Pre-processor directives to compile program for straight AIC echo, AIC echo with notch filter, FM1 (demodulation using "small-angle approx"), FM2 (demod using arcsin/arccos), or FSK. */ #define CT_ECHO 0 #define CT_NOTCH 1 #define CT_FM1 2 #define CT_FM2 3 #define CT_FSK 4 /* assign COMPILE_TYPE the desired program function (listed above, CT_xxx) and re-compile */ #define COMPILE_TYPE CT_FM1 #if COMPILE_TYPE == CT_ECHO #define COMPILE_STRING "STRAIGHT AIC ECHO" #elif COMPILE_TYPE == CT_NOTCH #define COMPILE_STRING "AIC ECHO WITH NOTCH" #elif COMPILE_TYPE == CT_FM1 #define COMPILE_STRING "FM1 (demod with 'small-angle approx')" #elif COMPILE_TYPE == CT_FM2 #define COMPILE_STRING "FM2 (demod with arcsin/arccos)" #elif COMPILE_TYPE == CT_FSK #define COMPILE_STRING "FSK" #else #define COMPILE_STRING "ERROR! Invalid COMPILE_TYPE!" #error "Macro COMPILE_TYPE not assigned a valid program function" #endif /*****************************************************************************************/ #define OUTPUT_GAIN 0 /* # of bits to right-shift demod signal for output */ #define CARRIER 0 /*#define CARRIER 3600*/ /* use when displaying I,Q values */ #define HALF_BUFFER_SIZE 64 /* HALF_BUFFER_SIZE = BUFFER_SIZE / 2 */ #define HALF_BUFFER_MASK 63 /* HALF_BUFFER_SIZE = HALF_BUFFER_SIZE - 1 */ #define SIN_TABLE_SIZE 256 /* size of sin table */ #define SIN_TABLE_MASK 255 /* mask for sin table */ #define ASIN_TABLE_SIZE 128 /* size of arcsin table */ #define ASIN_TABLE_MASK 127 /* mask for arcsin table */ #define LP_FIL_COF 15 /* LP Filter coefficient for demod output */ /* = 0.1111 (in binary) */ #define LP_SHIFT 4 /* how much to shift back after multiplying by LP_FIL_COF */ #define FSK_DEV 5000 /* fsk deviation frequency*/ #define FSK_TABLE_SIZE 2 /* bit->level lookup table size */ #define FSK_SAMPLES 4 /* # of samples per symbol */ /*****************************************************************************************/ //-------------------------------------- /* Declare aic function prototypes */ void init_aic(void); void init_c541(void); inline void disable_ints(void); inline void enable_ints(void); /* The EVM uses address 14 (bit 15) of IO space for AIC reset */ volatile ioport unsigned port14; //-------------------------------------- /* function protos for main */ void init_sin_table(); void init_asin_table(); void do_mod(); void do_demod(); inline int rescale_for_asin(int a_number); void do_demod2(); void do_echo(); void init_notch_filter(); void do_notch_filter(); void init_fsk(); void do_fsk(); void do_defsk(); /*****************************************************************************************/ /* input and output buffer actually declared in ints541.c */ extern int input_buffer[BUFFER_SIZE]; /* modulation: for incoming message samples */ extern int output_buffer[BUFFER_SIZE]; /* demod: for outgoing demodulated samples */ extern int input_index; /* index for input buffer */ /*****************************************************************************************/ // declare global arrays int I_vals[HALF_BUFFER_SIZE]; /* modulation: I values */ int Q_vals[HALF_BUFFER_SIZE]; /* modulation: Q values */ int sin_table[SIN_TABLE_SIZE]; /* declare sin lookup table */ int asin_table[ASIN_TABLE_SIZE]; /* declare arcsin lookup table */ int fsk_table[FSK_TABLE_SIZE]; /* declare FSK bit->level lookup table */ // declare global vars int mod_index=0; /* index for I/Q values arrays */ int output_index=0; /* index for output buffer */ /*****************************************************************************************/ /*****************************************************************************************/ void main(void) { int junk_sample; printf("\nFM/FSK TRANSMITTER & RECEIVER\n"); printf("Currently compiled for "); printf(COMPILE_STRING "\n\n"); init_c541(); disable_ints(); /* Turn off all maskable interrupts */ /****************************************************************/ /* Warning: Initialize any long arrays before turning on the */ /* AIC. The AIC can't wait for samples to be written into */ /* its DXR. They must be ready when requested. The initiali- */ /* zation can be done here. */ /****************************************************************/ init_asin_table(); init_sin_table(); init_notch_filter(); init_fsk(); // now we continue to initialize hardware init_aic(); IFR = 0xFFFF; /* Clear any pending interrupt requests */ junk_sample=DRR1; /* Clear DRR register so AIC would trigger interrupt */ enable_ints(); /* Allow interrupts to be serviced */ /*****************************************************************/ /* Now the C541 and AIC are initialized to your desired state. */ /* Include the program to accomplish your desired task below. */ /*****************************************************************/ while(1) /* dead-loop to allow program to run */ { while((input_index & HALF_BUFFER_MASK) != 0); /* dead-loop until frame complete */ /* an input frame has been completely filled */ /* caution: if mod/demod occur SO fast that they complete BEFORE another sample occurs, input_index will STILL be at the frame boundary, and mod/demod will be invoked AGAIN! Not a likely occurence, however. */ #if COMPILE_TYPE == CT_ECHO do_echo(); /* AIC echoing */ #endif #if COMPILE_TYPE == CT_NOTCH do_notch_filter();/* AIC notch filter */ #endif #if COMPILE_TYPE == CT_FSK do_fsk(); do_defsk(); #endif #if COMPILE_TYPE == CT_FM1 do_mod(); /* calculate I and Q values for completed input frame */ do_demod(); /* perform demodulation for completed frame */ #endif #if COMPILE_TYPE == CT_FM2 do_mod(); /* calculate I and Q values for completed input frame */ do_demod2(); /* alt way of demodulation */ #endif } /* end of infinite program loop */ } /*****************************************************************************************/ /*****************************************************************************************/ /* perform FIR notch filtering at 3000-4500Hz. See notch.h for filter spec uses 54xDSPlib to do FIR filter */ // init delay buffer void init_notch_filter(){ int lcv; for (lcv=0; lcvlevel conversion void init_fsk(){ fsk_table[0]=FSK_DEV; fsk_table[1]=-FSK_DEV; } /*****************************************************************************************/ /* creates FSK data using FSK_SAMPLES per symbol. Each symbol is a bit uses a togglebit and ignores AIC data CAUTION: IT MOSTLY WORKS, BUT SOMETIMES WILL GIVE ERRONEOUS RESULTS I HAVE NOT YET DEBUGGED IT FULLY. things to check for 1) when the angle crosses 0 or 2*pi boundary, the result could be very wrong. */ void do_fsk(){ static long int long_msg_angle=0; /* accumulator for integration of message */ static int togglebit=0; int index, index2, totalindex; int msg_angle; for (index=0; index<(HALF_BUFFER_SIZE / FSK_SAMPLES); index++) { // toggle that togglebit togglebit = (togglebit ^ 1) & 1; // calculate the samples for one symbol for (index2=0; index2> 9) & SIN_TABLE_MASK; // calculate how far into the half_buffer we are totalindex=(index * FSK_SAMPLES) + index2; /* take sin() of msg_angle */ Q_vals[totalindex]=sin_table[msg_angle]; /* take cos() of msg_angle using sin() table */ msg_angle+=64; /* offset by pi/4 */ msg_angle=msg_angle & SIN_TABLE_MASK; /* wrap around 2pi [mod 256] */ I_vals[totalindex]=sin_table[msg_angle]; } } mod_index = mod_index & BUFFER_MASK; /* wrap index about buffer */ } /*****************************************************************************************/ void do_defsk(){ /* holds prev values for LP filters */ static int prev_demod=0; static int prev2_demod=0; static int prev_I_val=0; static int prev_Q_val=0; int demod_angle; int index, index2, totalindex; int result; for (index=0; index<(HALF_BUFFER_SIZE / FSK_SAMPLES); index++) { for (index2=0; index2>14; prev_I_val=I_vals[totalindex]; prev_Q_val=Q_vals[totalindex]; if (index2==1){ result=(demod_angle > 0); // silly output. it doesn't really show anything output_buffer[output_index++] = result * 5000; } /* perform LP filter also */ // output_buffer[output_index++]=(demod_angle+((prev_demod*LP_FIL_COF) >> LP_SHIFT)+ // ((prev2_demod*LP_FIL_COF) >> LP_SHIFT)) << OUTPUT_GAIN; prev2_demod=prev_demod; prev_demod=demod_angle; } } output_index = output_index & BUFFER_MASK; /* wrap index about buffer */ } /*****************************************************************************************/ /*****************************************************************************************/ /* do_modulation: takes samples from input_buffer[], integrates them, and calculates I and Q values. I and Q values stored in their respective arrays. Integration is performed using a message angle accumulator (double-precision) that sums up message samples. Note that no mask is used to wrap this long_msg_angle variable -- thus, it may overflow given a message that does not have equal positive and negative amplitudes. msg_angle itself is a number between 0 and 255 and acts as the index to the sin table (0..255 maps directly to 0..2pi). Note that this routine is hard-coded for input range of -8192 to 8192, resolution of 256 samples for 2*pi. */ void do_mod() { static long int long_msg_angle=0; /* accumulator for integration of message */ int index; int msg_angle; for (index=0; index> 9) & SIN_TABLE_MASK; /* take sin() of msg_angle */ Q_vals[index]=sin_table[msg_angle]; /* take cos() of msg_angle using sin() table */ msg_angle+=64; /* offset by pi/4 */ msg_angle=msg_angle & SIN_TABLE_MASK; /* wrap around 2pi [mod 256] */ I_vals[index]=sin_table[msg_angle]; } mod_index = mod_index & BUFFER_MASK; /* wrap index about buffer */ } /*****************************************************************************************/ /* do_demod: take I and Q values and perform demodulation to get original message. Store demodulated signal in output buffer for transmission. Note that the I and Q values are 14-bit numbers. Thus their product will be, at most, 27-bits (26-bits plus 1 sign bit). Long ints are used to prevent overflow; a right shift by 14 bits puts the significant part of the result in demod_angle. */ void do_demod() { /* holds prev values for LP filters */ static int prev_demod=0; static int prev2_demod=0; static int prev_I_val=0; static int prev_Q_val=0; int demod_angle; int index; for (index=0; index>14; prev_I_val=I_vals[index]; prev_Q_val=Q_vals[index]; /* perform LP filter also */ output_buffer[output_index++]=(demod_angle+((prev_demod*LP_FIL_COF) >> LP_SHIFT)+ ((prev2_demod*LP_FIL_COF) >> LP_SHIFT)) << OUTPUT_GAIN; prev2_demod=prev_demod; prev_demod=demod_angle; } output_index = output_index & BUFFER_MASK; /* wrap index about buffer */ } /*****************************************************************************************/ /* Code below implements alternate demodulation technique (arcsin/arccos) */ /* This method results in a demodulated signal with more noise than above, however. */ /* Note requirement of global variable, int prev_angle */ //cheezy function to rescale a value down to the range of the arcsin // table (0-127) inline int rescale_for_asin(int a_number){ return ((a_number >> 7) & ASIN_TABLE_MASK); } /*****************************************************************************************/ int lookup_acos(int angle){ // tmp_val required... donno why. otherwise, demod signal looks funny int tmp_val; tmp_val=rescale_for_asin(-1*angle); return (asin_table[tmp_val]+64) & SIN_TABLE_MASK; } /*****************************************************************************************/ void do_demod2(){ static int prev_angle=0; int demod_angle; int index; for (index=0; index=0){ // angle is in 1st or 2nd quadrant demod_angle=lookup_acos(I_vals[index]); } else{ // angle is in 3rd or 4th quadrant if (I_vals[index]>0){ // angle is in 4th quadrant demod_angle=asin_table[rescale_for_asin(Q_vals[index])]; } else{ // angle is in 3rd quadrant (383=255+128) demod_angle=383-asin_table[rescale_for_asin(Q_vals[index])]; } } // warning: below does not properly handle angle wrapping around 360 degrees! // if angle goes from 355 to 5 degrees, looks like a change of -350 degrees... // if we can assume small angle changes, then take smaller angle change. // (10 degrees instead of -350 degrees) output_buffer[output_index++]=(demod_angle-prev_angle-CARRIER) << 8; prev_angle=demod_angle; } output_index = output_index & BUFFER_MASK; /* wrap index about buffer */ } /*****************************************************************************************/ void init_sin_table(){ sin_table[0]=0; sin_table[1]=201; sin_table[2]=402; sin_table[3]=603; sin_table[4]=803; sin_table[5]=1003; sin_table[6]=1202; sin_table[7]=1400; sin_table[8]=1598; sin_table[9]=1795; sin_table[10]=1990; sin_table[11]=2185; sin_table[12]=2378; sin_table[13]=2569; sin_table[14]=2759; sin_table[15]=2948; sin_table[16]=3135; sin_table[17]=3319; sin_table[18]=3502; sin_table[19]=3683; sin_table[20]=3861; sin_table[21]=4037; sin_table[22]=4211; sin_table[23]=4382; sin_table[24]=4551; sin_table[25]=4716; sin_table[26]=4879; sin_table[27]=5039; sin_table[28]=5196; sin_table[29]=5350; sin_table[30]=5501; sin_table[31]=5648; sin_table[32]=5792; sin_table[33]=5932; sin_table[34]=6069; sin_table[35]=6202; sin_table[36]=6332; sin_table[37]=6457; sin_table[38]=6579; sin_table[39]=6697; sin_table[40]=6811; sin_table[41]=6920; sin_table[42]=7026; sin_table[43]=7127; sin_table[44]=7224; sin_table[45]=7316; sin_table[46]=7405; sin_table[47]=7488; sin_table[48]=7567; sin_table[49]=7642; sin_table[50]=7712; sin_table[51]=7778; sin_table[52]=7838; sin_table[53]=7894; sin_table[54]=7946; sin_table[55]=7992; sin_table[56]=8034; sin_table[57]=8070; sin_table[58]=8102; sin_table[59]=8129; sin_table[60]=8152; sin_table[61]=8169; sin_table[62]=8181; sin_table[63]=8189; sin_table[64]=8191; sin_table[65]=8189; sin_table[66]=8181; sin_table[67]=8169; sin_table[68]=8152; sin_table[69]=8129; sin_table[70]=8102; sin_table[71]=8070; sin_table[72]=8034; sin_table[73]=7992; sin_table[74]=7946; sin_table[75]=7894; sin_table[76]=7838; sin_table[77]=7778; sin_table[78]=7712; sin_table[79]=7642; sin_table[80]=7567; sin_table[81]=7488; sin_table[82]=7405; sin_table[83]=7316; sin_table[84]=7224; sin_table[85]=7127; sin_table[86]=7026; sin_table[87]=6920; sin_table[88]=6811; sin_table[89]=6697; sin_table[90]=6579; sin_table[91]=6457; sin_table[92]=6332; sin_table[93]=6202; sin_table[94]=6069; sin_table[95]=5932; sin_table[96]=5792; sin_table[97]=5648; sin_table[98]=5501; sin_table[99]=5350; sin_table[100]=5196; sin_table[101]=5039; sin_table[102]=4879; sin_table[103]=4716; sin_table[104]=4551; sin_table[105]=4382; sin_table[106]=4211; sin_table[107]=4037; sin_table[108]=3861; sin_table[109]=3683; sin_table[110]=3502; sin_table[111]=3319; sin_table[112]=3135; sin_table[113]=2948; sin_table[114]=2759; sin_table[115]=2569; sin_table[116]=2378; sin_table[117]=2185; sin_table[118]=1990; sin_table[119]=1795; sin_table[120]=1598; sin_table[121]=1400; sin_table[122]=1202; sin_table[123]=1003; sin_table[124]=803; sin_table[125]=603; sin_table[126]=402; sin_table[127]=201; sin_table[128]=0; sin_table[129]=-201; sin_table[130]=-402; sin_table[131]=-603; sin_table[132]=-803; sin_table[133]=-1003; sin_table[134]=-1202; sin_table[135]=-1400; sin_table[136]=-1598; sin_table[137]=-1795; sin_table[138]=-1990; sin_table[139]=-2185; sin_table[140]=-2378; sin_table[141]=-2569; sin_table[142]=-2759; sin_table[143]=-2948; sin_table[144]=-3135; sin_table[145]=-3319; sin_table[146]=-3502; sin_table[147]=-3683; sin_table[148]=-3861; sin_table[149]=-4037; sin_table[150]=-4211; sin_table[151]=-4382; sin_table[152]=-4551; sin_table[153]=-4716; sin_table[154]=-4879; sin_table[155]=-5039; sin_table[156]=-5196; sin_table[157]=-5350; sin_table[158]=-5501; sin_table[159]=-5648; sin_table[160]=-5792; sin_table[161]=-5932; sin_table[162]=-6069; sin_table[163]=-6202; sin_table[164]=-6332; sin_table[165]=-6457; sin_table[166]=-6579; sin_table[167]=-6697; sin_table[168]=-6811; sin_table[169]=-6920; sin_table[170]=-7026; sin_table[171]=-7127; sin_table[172]=-7224; sin_table[173]=-7316; sin_table[174]=-7405; sin_table[175]=-7488; sin_table[176]=-7567; sin_table[177]=-7642; sin_table[178]=-7712; sin_table[179]=-7778; sin_table[180]=-7838; sin_table[181]=-7894; sin_table[182]=-7946; sin_table[183]=-7992; sin_table[184]=-8034; sin_table[185]=-8070; sin_table[186]=-8102; sin_table[187]=-8129; sin_table[188]=-8152; sin_table[189]=-8169; sin_table[190]=-8181; sin_table[191]=-8189; sin_table[192]=-8191; sin_table[193]=-8189; sin_table[194]=-8181; sin_table[195]=-8169; sin_table[196]=-8152; sin_table[197]=-8129; sin_table[198]=-8102; sin_table[199]=-8070; sin_table[200]=-8034; sin_table[201]=-7992; sin_table[202]=-7946; sin_table[203]=-7894; sin_table[204]=-7838; sin_table[205]=-7778; sin_table[206]=-7712; sin_table[207]=-7642; sin_table[208]=-7567; sin_table[209]=-7488; sin_table[210]=-7405; sin_table[211]=-7316; sin_table[212]=-7224; sin_table[213]=-7127; sin_table[214]=-7026; sin_table[215]=-6920; sin_table[216]=-6811; sin_table[217]=-6697; sin_table[218]=-6579; sin_table[219]=-6457; sin_table[220]=-6332; sin_table[221]=-6202; sin_table[222]=-6069; sin_table[223]=-5932; sin_table[224]=-5792; sin_table[225]=-5648; sin_table[226]=-5501; sin_table[227]=-5350; sin_table[228]=-5196; sin_table[229]=-5039; sin_table[230]=-4879; sin_table[231]=-4716; sin_table[232]=-4551; sin_table[233]=-4382; sin_table[234]=-4211; sin_table[235]=-4037; sin_table[236]=-3861; sin_table[237]=-3683; sin_table[238]=-3502; sin_table[239]=-3319; sin_table[240]=-3135; sin_table[241]=-2948; sin_table[242]=-2759; sin_table[243]=-2569; sin_table[244]=-2378; sin_table[245]=-2185; sin_table[246]=-1990; sin_table[247]=-1795; sin_table[248]=-1598; sin_table[249]=-1400; sin_table[250]=-1202; sin_table[251]=-1003; sin_table[252]=-803; sin_table[253]=-603; sin_table[254]=-402; sin_table[255]=-201; } /*****************************************************************************************/ void init_asin_table(){ asin_table[0]=0; asin_table[1]=0; asin_table[2]=1; asin_table[3]=1; asin_table[4]=2; asin_table[5]=3; asin_table[6]=3; asin_table[7]=4; asin_table[8]=5; asin_table[9]=5; asin_table[10]=6; asin_table[11]=6; asin_table[12]=7; asin_table[13]=8; asin_table[14]=8; asin_table[15]=9; asin_table[16]=10; asin_table[17]=10; asin_table[18]=11; asin_table[19]=12; asin_table[20]=12; asin_table[21]=13; asin_table[22]=14; asin_table[23]=14; asin_table[24]=15; asin_table[25]=16; asin_table[26]=16; asin_table[27]=17; asin_table[28]=18; asin_table[29]=19; asin_table[30]=19; asin_table[31]=20; asin_table[32]=21; asin_table[33]=21; asin_table[34]=22; asin_table[35]=23; asin_table[36]=24; asin_table[37]=24; asin_table[38]=25; asin_table[39]=26; asin_table[40]=27; asin_table[41]=28; asin_table[42]=28; asin_table[43]=29; asin_table[44]=30; asin_table[45]=31; asin_table[46]=32; asin_table[47]=33; asin_table[48]=34; asin_table[49]=35; asin_table[50]=36; asin_table[51]=37; asin_table[52]=38; asin_table[53]=39; asin_table[54]=40; asin_table[55]=41; asin_table[56]=43; asin_table[57]=44; asin_table[58]=45; asin_table[59]=47; asin_table[60]=49; asin_table[61]=51; asin_table[62]=53; asin_table[63]=56; asin_table[64]=192; asin_table[65]=199; asin_table[66]=202; asin_table[67]=204; asin_table[68]=206; asin_table[69]=208; asin_table[70]=210; asin_table[71]=211; asin_table[72]=212; asin_table[73]=214; asin_table[74]=215; asin_table[75]=216; asin_table[76]=217; asin_table[77]=218; asin_table[78]=219; asin_table[79]=220; asin_table[80]=221; asin_table[81]=222; asin_table[82]=223; asin_table[83]=224; asin_table[84]=225; asin_table[85]=226; asin_table[86]=227; asin_table[87]=227; asin_table[88]=228; asin_table[89]=229; asin_table[90]=230; asin_table[91]=231; asin_table[92]=231; asin_table[93]=232; asin_table[94]=233; asin_table[95]=234; asin_table[96]=234; asin_table[97]=235; asin_table[98]=236; asin_table[99]=236; asin_table[100]=237; asin_table[101]=238; asin_table[102]=239; asin_table[103]=239; asin_table[104]=240; asin_table[105]=241; asin_table[106]=241; asin_table[107]=242; asin_table[108]=243; asin_table[109]=243; asin_table[110]=244; asin_table[111]=245; asin_table[112]=245; asin_table[113]=246; asin_table[114]=247; asin_table[115]=247; asin_table[116]=248; asin_table[117]=249; asin_table[118]=249; asin_table[119]=250; asin_table[120]=250; asin_table[121]=251; asin_table[122]=252; asin_table[123]=252; asin_table[124]=253; asin_table[125]=254; asin_table[126]=254; asin_table[127]=255; } /*****************************************************************************************/ /*****************************************************************************************/ /*****************************************************************/ /* init_aic() initializes the TLC320AC01C analog interface */ /* circuit control register. */ /*---------------------------------------------------------------*/ void init_aic(void) { /*****************************************************************/ /* Declare the AIC register scratch-pad variables. The */ /* structures are defined in aic_01c.h. */ /*****************************************************************/ AIC_REGISTER_STD aic_register_1; /* A register */ AIC_REGISTER_STD aic_register_2; /* B register */ AIC_REGISTER_AP aic_register_3; /* A' register */ AIC_REGISTER4 aic_register_4; /* Amplifier gain-select register */ AIC_REGISTER5 aic_register_5; /* Analog configuration register */ AIC_REGISTER6 aic_register_6; /* Digital configuration register */ AIC_REGISTER_STD aic_register_7; /* Frame-sync delay register */ AIC_REGISTER_STD aic_register_8; /* Frame-sync number register */ /*****************************************************************/ /*****************************************************************/ /* Formulas for the AIC sampling rate, fs, lowpass filter */ /* cutoff frequency, f(LP), highpass filter cutoff frequency, */ /* f(HP), and serial data shift clock rate, SCLK. */ /* */ /* f(MCLK) = 10.368 MHz = input master clock frequency from */ /* a crystal oscillator */ /* */ /* SCLK = serial shift clock= f(MCLK)/4 = 2.592 MHz */ /* */ /* FCLK = switched capcitor filter clock = f(MCLK)/(2xA) */ /* */ /* With no advance/retard, i.e., control bits = 00 */ /* fs = sampling frequency = f(MCLK)/ (2xAxB) */ /* With control bits = 01 */ /* fs = f(MCLK)/(2xAxB + A') */ /* With control bits = 10 */ /* fs = f(MCLK)/(2xAxB - A') */ /* */ /* f(LP) = lowpass filter cutoff = FCLK/40 = f(MCLK)/(80xA) */ /* */ /* f(HP) = highpass filter cutoff = fs/200 = f(MCLK)/(400xAxB) */ /*****************************************************************/ /*---------------------------------------------------------------*/ /* Set the A Register scratchpad */ /*---------------------------------------------------------------*/ aic_register_1.register_data = 12; /* A = 12 -> FCLK = 432 kHz */ /* f(LP) = 10.8 kHz */ //aic_register_1.register_data = 18; /* A = 18 -> FCLK = 288 kHz */ // /* f(LP) = 7.2 kHz */ //aic_register_1.register_data = 36; /* A = 36 -> FCLK = 144 kHz */ // /* f(LP) = 3.6 kHz */ aic_register_1.register_address = 1; aic_register_1.r_notw = 0; /* Write to register */ aic_register_1.control_bits = 0; /* no advance/retard (see AIC */ /* manual the other three options) */ /*---------------------------------------------------------------*/ /* Set the B Register scratchpad */ /*---------------------------------------------------------------*/ //aic_register_2.register_data = 20; /* B = 20 -> fs = ? kHz */ /* f(HP) = ? Hz */ aic_register_2.register_data = 18; /* B = 18 -> fs = 24 kHz */ /* f(HP) = 120 Hz */ //aic_register_2.register_data = 10; /* B = 10 -> fs = ? kHz */ /* f(HP) = ? Hz */ aic_register_2.register_address = 2; aic_register_2.r_notw = 0; aic_register_2.control_bits = 0; /*---------------------------------------------------------------*/ /* Set the A' Register scratchpad. The default reset value is */ /* A' = 0. */ /*---------------------------------------------------------------*/ aic_register_3.register_data = 0; /* A' = 0 */ aic_register_3.register_address = 3; aic_register_2.r_notw = 0; aic_register_2.control_bits = 0; /*---------------------------------------------------------------*/ /* Set Amplifier Gain-Select Register scratchpad. */ /* DS07,...,DS00 reset default = 00000101 */ /*---------------------------------------------------------------*/ aic_register_4.analog_out_gain = 0; /* ? dB */ aic_register_4.analog_in_gain = 0; /* ? dB */ aic_register_4.mon_out_gain = 0; /* squelch */ aic_register_4.ds0607 = 0; /* don't cares */ aic_register_4.register_address= 4; aic_register_4.r_notw = 0; aic_register_4.control_bits = 0; /*---------------------------------------------------------------*/ /* Set Analog Configuration Register scratchpad. */ /* DS07,...,DS00 reset default = xxxx0001 */ /*---------------------------------------------------------------*/ aic_register_5.input_select = 1; /* Enable IN+ and IN- */ aic_register_5.highpass_filt = 0; /* Higpass filter enabled*/ aic_register_5.ds03 = 0; /* Must be 0 */ aic_register_5.ds7_4 = 0; /* Don't cares */ aic_register_5.register_address = 5; aic_register_5.r_notw = 0; aic_register_5.control_bits = 0; /*---------------------------------------------------------------*/ /* Set Digital Configuration Register scratchpad */ /* DS07,...,DS00 reset default = 00000000 */ /*---------------------------------------------------------------*/ aic_register_6.power_down = 0; /* Power-down external */ aic_register_6.software_reset = 0; /* Inactive reset */ aic_register_6.second_comm = 0; /* Normal operation */ aic_register_6.ignore_primary = 0; /* Normal operation */ aic_register_6.fsd_disable = 0; /* FSD enable */ aic_register_6.adc_free_run = 0; /* free run inactive */ aic_register_6.ds8_7 = 0; /* Don't cares */ aic_register_6.register_address = 6; aic_register_6.r_notw = 0; aic_register_6.control_bits = 0; /*---------------------------------------------------------------*/ /* Set Frame-Sync Delay Register scratchpad */ /* DS07,...,DS00 reset default = 00000000 */ /*---------------------------------------------------------------*/ aic_register_7.register_data = 0; aic_register_7.register_address = 7; aic_register_7.r_notw = 0; aic_register_7.control_bits = 0; /*---------------------------------------------------------------*/ /* Set Frame-Sync Number Register scratchpad */ /* DS07,...,DS00 reset default = 00000001 */ /*---------------------------------------------------------------*/ aic_register_8.register_data = 1; /* Number of frame syncs */ aic_register_8.register_address = 8; aic_register_8.r_notw = 0; aic_register_8.control_bits = 0; /*---------------------------------------------------------------*/ /* Put AIC in reset by setting bit 15 of IO port 14 to 0 */ port14 = 0x0; /* Initialize Serial Port Control Register 1 (SPC1) as follows: */ /* F0 = 0, 16-bit mode bit 2 */ /* FSM = 1, Burst Mode bit 3 */ /* MCM = 0, External Clock Source bit 4 */ /* TXM = 0, External Frame Sync bit 5 */ /* ~XRST = 0, Reset Transmitter and halt bit 6 */ /* ~RRST = 0, Reset Receiver and halt bit 7 */ /* SOFT = 1, On halt, stop clock after */ /* current word sent bit 14 */ /* all other bits are 0 */ /* SPC1 = [0100 0000 0000 1000] = 0x4008 */ SPC1 = 0x4008; /* Halt, reset, set mode as above */ /* Now set ~XRST = ~RRST = 1 to start serial port */ /* SPC1 = [0100 0000 1100 1000] = 0x40C8 */ SPC1 = 0x40C8; /* Start serial port 1 */ DXR1 = 0; /* Write a dummy word to serial port */ /* Pull AIC out of reset by setting bit 15 to 1 */ port14 = 0x8000; /* Program the AIC registers */ while(!(SPC1 & 0x800)); /* Wait for XRDY bit = 1 */ DXR1 = 0x0003; /* Tell AIC to request a secondary command word */ while(!(SPC1 & 0x800)); /* Wait for XRDY bit = 1 */ DXR1 = *( (int *) &aic_register_1 ); /* Set A Register */ while(!(SPC1 & 0x800)); /* Wait for XRDY = 1 */ DXR1 = 0x0003; /* Request a command word */ while(!(SPC1 & 0x800)); /* Wait for XRDY bit = 1 */ DXR1 = *( (int*) &aic_register_2 ); /* Set B Register */ /****************************************************************/ /* All the remaining AIC registers are left at their default */ /* reset values. */ /****************************************************************/ IMR = 0x40; /* Enable Serial Port 1 reciever interrupts by */ /* setting bit 6 (RINT1) in the Interrupt Mask */ /* Register (IMR) */ } /* end of init_aic() */ void init_c541(){ /* Set 0 wait states for external memory and 2 for IO */ /* Software Wait-State Register (SWWSR) Bit Summary */ /* Reset */ /* Bit Name Value Function */ /* 15 Reserved 0 /* 14-12 I/O 1 Wait states for I/O space 0000-FFFFh */ /* 11-9 Data 1 Wait states for data space 8000-FFFFh */ /* 8-6 Data 1 Wait states for data space 0000-7FFFh */ /* 5-3 Program 1 Wait states for program space 8000-FFFFh */ /* 2-0 Program 1 Wait states for program space 0000-7FFFh */ SWWSR = 0x2000; /* Set OVLY bit to overlay onchip RAM onto program space. */ /* Set bit 5 of Processor Mode Status Register (PMST) */ PMST |= 0x0020; /* Clear all flags in the Interrupt Flags Register (IFR) */ IFR = 0xFFFF; } /* End of init_c541() */ /* Function to disable all maskable interrupts */ void inline disable_ints() { asm( " ssbx INTM"); } /* Function to enable all maskable interrupts */ void inline enable_ints() { asm( " rsbx INTM"); }