/* * ======== My lab02.c ======== */ /* * ======== Include files ======== */ #include <c6x.h> // C6000 compiler definitions #include <csl.h> #include <csl_edma.h> #include <csl_irq.h> #include <bsl.h> #include <bsl_dip.h> #include <bsl_led.h> #include "lab02cfg.h" #include "coeff.h" /* * ======== Prototypes ======== */ void initEmif(void); void initEdma(void); void initHwi(void); extern void blockSine(short *buf, int len); void edmaHwi(void); void FIRfilter(int *inbuf, int *outbuf, float *coeff, int buffSize, int Norder); void processBuffer(void); // 6-16 /* * ======== Declarations ======== */ #define PING 0 // 5-10 #define PONG 1 // 5-10 #define BUFFSIZE 256 /* * ======== Global Variables ======== */ int gBufferXmtPing[BUFFSIZE]; // 5-10 int gBufferXmtPong[BUFFSIZE]; int gBufferRcvPing[BUFFSIZE]; int gBufferRcvPong[BUFFSIZE]; #pragma DATA_SECTION(gDelay, ".far"); #define gDELAYSIZE 12000 int gDelay[gDELAYSIZE]; int gIndex=0; EDMA_Handle hEdmaXmt; EDMA_Handle hEdmaReloadXmtPing; // 3-23 EDMA_Handle hEdmaReloadXmtPong; // 5-10 EDMA_Handle hEdmaRcv; EDMA_Handle hEdmaReloadRcvPing; // 3-23 EDMA_Handle hEdmaReloadRcvPong; // 5-10 short gXmtChan; short gRcvChan; // 4-16 /**************************************************************\ * The "EDMA Config" type data structure holds the * parameters to be programmed into a EDMA channel. * Register Make (RMK) macros build a 32-bit unsigned int; * below it is used to build the Options (OPT) register. * The OF macros provide the proper typecasting needed for * the EDMA Config data structure. * * To locate the structure below, use: * * Help-->User Manuals--> * SPRU401 - TMS320C6000 Chip Support Library API Reference Guide * * 1. Open the SPRU401 .pdf file. * 2. Search for "EDMA_OPT_field_symval" and go to the link * * Notice that Table B-23 specifies how to build the * OPT RMK structure. If you want to know the options for * each field, just look at the table. * * You can locate the other Config fields by searching for: * * "EDMA_SRC_field_symval" \**************************************************************/ EDMA_Config gEdmaConfigXmt = { // 3-12 EDMA_OPT_RMK( EDMA_OPT_PRI_LOW, // Priority? // EDMA_OPT_ESIZE_16BIT, // Element size? EDMA_OPT_ESIZE_32BIT, // Element size? EDMA_OPT_2DS_NO, // 2 dimensional source? EDMA_OPT_SUM_INC, // Src update mode? EDMA_OPT_2DD_NO, // 2 dimensional dest? EDMA_OPT_DUM_NONE, // Dest update mode? 4-16 EDMA_OPT_TCINT_YES, // Cause EDMA interrupt? EDMA_OPT_TCC_OF(0),// Transfer complete code? EDMA_OPT_LINK_YES, // Enable link parameters? EDMA_OPT_FS_NO // Use frame sync? 4-16 ), EDMA_SRC_OF(gBufferXmtPing), // src address? 5-10 EDMA_CNT_OF(BUFFSIZE), // Count = buffer size EDMA_DST_OF(0), // dest address? 4-16 EDMA_IDX_OF(0), // frame/element index value? EDMA_RLD_OF(0) // reload }; EDMA_Config gEdmaConfigRcv = { // 4-16 EDMA_OPT_RMK( EDMA_OPT_PRI_LOW, // Priority? // EDMA_OPT_ESIZE_16BIT, // Element size? EDMA_OPT_ESIZE_32BIT, // Element size? EDMA_OPT_2DS_NO, // 2 dimensional source? EDMA_OPT_SUM_NONE, // Src update mode? 4-16 EDMA_OPT_2DD_NO, // 2 dimensional dest? EDMA_OPT_DUM_INC, // Dest update mode? 4-16 EDMA_OPT_TCINT_YES, // Cause EDMA interrupt? EDMA_OPT_TCC_OF(0),// Transfer complete code? EDMA_OPT_LINK_YES, // Enable link parameters? EDMA_OPT_FS_NO // Use frame sync? 4-16 ), EDMA_SRC_OF(0), // src address? EDMA_CNT_OF(BUFFSIZE), // Count = buffer size EDMA_DST_OF(gBufferRcvPing), // dest address? 4-16, 5-10 EDMA_IDX_OF(0), // frame/element index value? EDMA_RLD_OF(0) // reload }; /* * ======== main ======== */ void main() { int i; initEmif(); // Dummy function - see note below for(i=0; i<BUFFSIZE;i++) { // 4-16 gBufferXmtPing[i]=0; // 5-10 gBufferXmtPong[i]=0; } for(i=0; i<gDELAYSIZE; i++) gDelay[i] = 0; MCBSP_enableXmt(hMcbsp1); // 4-14 MCBSP_enableRcv(hMcbsp1); // 4-14 while( !(MCBSP_rrdy(hMcbsp1))); // Wait for McBSP to be ready. initEdma(); initHwi(); } /* * ======== initEmif ======== * Configure External Memory Interface (EMIF) * * We have a dummy function here to setup the EMIF. In a "real" * system you would be required to setup the EMIF but in our * development system CCS sets up the memory for us (refer to * the DSK6211_6711.gel file for the CCS script that * accomplishes this task. */ void initEmif(void){ } void initEdma(void){ // Setup transmit side // hEdmaXmt = EDMA_open(EDMA_CHA_XEVT0, EDMA_OPEN_RESET); // 4-17 hEdmaXmt = EDMA_open(EDMA_CHA_XEVT1, EDMA_OPEN_RESET); // 4-17 hEdmaReloadXmtPong = EDMA_allocTable(-1); // 3-23 hEdmaReloadXmtPing = EDMA_allocTable(-1); // 5-11 gEdmaConfigXmt.dst = MCBSP_getXmtAddr(hMcbsp1); // 4-17 gXmtChan = EDMA_intAlloc(-1); gEdmaConfigXmt.opt |= EDMA_FMK(OPT, TCC, gXmtChan); EDMA_config(hEdmaXmt, &gEdmaConfigXmt); EDMA_config(hEdmaReloadXmtPing, &gEdmaConfigXmt); // 3-23, 5-11 gEdmaConfigXmt.src = EDMA_SRC_OF(gBufferXmtPong); // 5-11 EDMA_config(hEdmaReloadXmtPong, &gEdmaConfigXmt); // 5-11 EDMA_link(hEdmaXmt, hEdmaReloadXmtPong); // 3-23 EDMA_link(hEdmaReloadXmtPong, hEdmaReloadXmtPing); // 3-23, 5-11 EDMA_link(hEdmaReloadXmtPing, hEdmaReloadXmtPong); // 3-23, 5-11 // Setup receive side // hEdmaRcv = EDMA_open(EDMA_CHA_REVT0, EDMA_OPEN_RESET); // 4-17 hEdmaRcv = EDMA_open(EDMA_CHA_REVT1, EDMA_OPEN_RESET); // 4-17 hEdmaReloadRcvPing = EDMA_allocTable(-1); // 3-23, 5-11 hEdmaReloadRcvPong = EDMA_allocTable(-1); // 3-23 gEdmaConfigRcv.src = MCBSP_getRcvAddr(hMcbsp1); // 4-17 gRcvChan = EDMA_intAlloc(-1); gEdmaConfigRcv.opt |= EDMA_FMK(OPT, TCC, gRcvChan); EDMA_config(hEdmaRcv, &gEdmaConfigRcv); EDMA_config(hEdmaReloadRcvPing, &gEdmaConfigRcv); // 3-23, 5-11 gEdmaConfigRcv.dst = EDMA_DST_OF(gBufferRcvPong); // 5-11 EDMA_config(hEdmaReloadRcvPong, &gEdmaConfigRcv); // 5-11 EDMA_link(hEdmaRcv, hEdmaReloadRcvPong); // 3-23, 5-11 EDMA_link(hEdmaReloadRcvPong, hEdmaReloadRcvPing); // 3-23, 5-11 EDMA_link(hEdmaReloadRcvPing, hEdmaReloadRcvPong); // 3-23, 5-11 // Clear pending flags in the EDMA's CIPR register. 4-18 EDMA_intClear(gXmtChan); // Clear spurious interrupts 3-22 EDMA_intClear(gRcvChan); // Clear spurious interrupts 3-22 // Enable the interupts from the EDMA channels (CIER register) to the CPU 4-18 EDMA_intEnable(gXmtChan); EDMA_intEnable(gRcvChan); // Enable the EDMA channels themselves 4-18 EDMA_enableChannel(hEdmaXmt); EDMA_enableChannel(hEdmaRcv); } void edmaHwi(void) { // 3-21 static Uint32 pingOrPong = PING; // 5-12 /* 4-19 EDMA_intClear(0); blockSine(gBufferXmt, BUFFSIZE); // Fill the buffer with sine data EDMA_setChannel(hEdmaXmt); */ if(EDMA_intTest(gRcvChan) & EDMA_intTest(gXmtChan)) { // 4-19 // load(gLoadValue); // 5-8 // Clear both CIPR bits. EDMA_intClear(gRcvChan); EDMA_intClear(gXmtChan); if(pingOrPong == PING) { // 6-17 SWI_or(&processBufferSwi, PING); pingOrPong = PONG; } else { SWI_or(&processBufferSwi, PONG); pingOrPong = PING; } } } void initHwi(void) { IRQ_enable(IRQ_EVT_EDMAINT); // HWI_INT8 3-11 IRQ_globalEnable(); // turn on interrupts globally 3-11 } void processBuffer(void) { // 6-16 int *gBufferRcv, *gBufferXmt; // Points to the ping or pong buffer. Uint32 pingPong = SWI_getmbox(); // 6-16 if(pingPong == PING) { // Make sure we're pointing to the right buffer. gBufferRcv = gBufferRcvPing; gBufferXmt = gBufferXmtPing; } else { gBufferRcv = gBufferRcvPong; gBufferXmt = gBufferXmtPong; } if(DIP_get(DIP_1) == 0) addSine(gBufferRcv, BUFFSIZE); if(DIP_get(DIP_3) == 0) FIRfilter(gBufferRcv, gBufferXmt, coeff, BUFFSIZE, NUMCOEFFS-1); else copyData(gBufferRcv, gBufferXmt, BUFFSIZE); } /* The following code is run by the period timer. It checks the MSB (not the sign bit). If it is 1, it turns the LED on. This is a way to see if there is clipping. */ void blinkLeds(void) { int i; short lmax=0, ltmp; short rmax=0, rtmp; for(i=0; i<BUFFSIZE; i++) { ltmp = (short) _abs(gBufferRcvPing[i]>>16); rtmp = (short) _abs(gBufferRcvPing[i]); lmax = lmax<ltmp ? ltmp: lmax; rmax = rmax<rtmp ? rtmp: rmax; } LOG_printf(&logTrace, "blinkLeds: max = %d, %d", lmax, rmax); // Turn LED on if MSB (not sign bit) is on. if(lmax & 0x4000) LED_on(LED_1); else LED_off(LED_1); if(rmax & 0x4000) LED_on(LED_3); else LED_off(LED_3); } /* This routine convolves the present and the Norder previous input samples with the Norder+1 FIR coefficients h(0) through h(Norder): y(n) = h(0)*x(n) + h(1)*x(n-1) + ... + h(Norder)*x(n-Norder) */ void FIRfilter(int *inbuf, int *outbuf, float *coeff, int buffSize, int Norder) { int intsamp,i,j; float floatsamp,sum; static float x[NUMCOEFFS]; for(j=0; j<buffSize; j++) { intsamp=inbuf[j]; /* read the input */ intsamp = intsamp & 0xffff; /* Mask right channel data (bottom 16 bits) */ if(intsamp & 0x8000) intsamp = intsamp | 0xffff0000; /* Sign extend right channel data */ floatsamp = (float) intsamp; /* Convert right channel to floating point */ /* Update past input sample array, where x[0] holds present sample, x[1] holds sample from 1 sample period ago, x[N] holds sample from N sampling periods ago. This time-consuming loop could be eliminated if circular buffering were to be employed. */ for(i=Norder; i >= 0;i--) x[i]=x[i-1]; x[0] = floatsamp; sum = 0.0; for(i=0; i<=Norder; i++) /* Perform FIR filtering (convolution) */ sum=sum+x[i]*coeff[i]; intsamp = ((int) sum) & 0xffff; /* Convert result back to integer form. */ outbuf[j] = intsamp << 16 | intsamp; /* Send to buffer (both channels ) */ } }