/*************************************************************************** convolve.c - perform a 3x3 convolution on a video data stream This program will define three pipes on the MV200: an acquisition, processing, and display pipe. The processing pipe will use the NMAC element on the AP device to perform a video rate 3x3 convolution. ***************************************************************************/ #include #include #define DISPLAYXSIZE 512L #define DISPLAYYSIZE 484L /* convolution pattern */ #define KERNELXSIZE 3 #define KERNELYSIZE 3 /* identify the devices used in this program */ dqLimitIPDevSet(AB AM AS AG AP); main() { DqSystem oSystem; DqIPDev oAb00, oAg00, oAs00; DqIPDev oAm00, oAm01, oAp00; DqSurf oAcqSrcSurf, oAcqDstSurf; DqSurf oProcSrcSurf, oProcDstSurf, oKernel; DqSurf oDispSrcSurf, oDispDstSurf; DqPipe oDispPipe, oAcqPipe, oProcPipe; DqRect tConvRect; /* convolution rectangle description */ DqByte Coefs[3][3]; /* 3x3 convolution kernel coefficients */ char pcUserInpBuf[80]; /* initialize the system and get handles for the devices */ dqInitEnv(); oSystem = dqCreateStdSys(); oAb00 = dqFindIPDev(oSystem, "ab00"); oAs00 = dqFindIPDev(oSystem, "as00"); oAg00 = dqFindIPDev(oSystem, "ag00"); oAp00 = dqFindIPDev(oSystem, "ap00"); oAm00 = dqFindIPDev(oSystem, "ab00:am00"); oAm01 = dqFindIPDev(oSystem, "ab00:am01"); /* set the data type checking to tolerant */ dqSetDTPDogma(DQ_DTP_TOLERANT); /************************* ACQUISITION PIPE **************************/ oAcqSrcSurf = dqCreateStdSizeSurf(oAs00, AS_ADC); dqAttachSurf(oAcqSrcSurf, AS_XMT); /* take signed data from the AS device */ dqSetDTT(oAs00, AS_DTM, DQ_DTT_X_SIGNED); /* use DQ_CSR for signed output from the AS device */ dqConnect(oAb00, DQ_CSR, AB_OP00); amSetRcvGateway20MHz(oAm00); oAcqDstSurf = dqCreateSameSizeSurf(oAm00, AM_MEM_R8,oAcqSrcSurf); dqAttachSurf(oAcqDstSurf,AM_RCV); /* create a continuously running pipe, arm and fire it off */ oAcqPipe = dqCreatePipe(oAcqDstSurf, DQ_TRG_CONTINUOUS); dqArmPipe(oAcqPipe, DQ_DSM_PIPE); dqFirePipe(oAcqPipe); /*********************** PROCESSING PIPE *****************************/ /* start with the data from the acquisition pipe */ oProcSrcSurf = dqDupSurf(oAcqDstSurf); dqAttachSurf(oProcSrcSurf, AM_XMT); /* because this is running into the cross point for processing the memory must output at 20 MHz. */ amSetXmtGateway20MHz(oAm00); dqConnect(oAb00, DQ_IMX0, AB_OP21); /* across to the NMAC input */ /* set the configuration for the NMAC element to 8x8 convolution */ dqConnect(oAp00, AP_SHIFT8, AP_NDLY_SRC); /* create a surface to define the kernel in the NMAC */ oKernel = dqCreateSurf(oAp00, AP_NMAC8, KERNELXSIZE, KERNELYSIZE); dqSetSurfBaseDT(oKernel, DQ_DT_SIGNED); /* everything will be signed */ dqAttachSurf(oKernel, AP_NMAC8); /* you have to attach to this also */ /* the host will write directly into the surface with the coeffient values. This rectangle is defined with respect to the center point. The default center point is the center pixel of the kernel. */ tConvRect.lXMin = -(KERNELXSIZE / 2); tConvRect.lXMax = KERNELXSIZE % 2 ? KERNELXSIZE / 2 : KERNELXSIZE / 2 - 1; tConvRect.lYMin = -(KERNELYSIZE / 2); tConvRect.lYMax = KERNELYSIZE % 2 ? KERNELYSIZE / 2 : KERNELYSIZE / 2 - 1; /* this defines a 3x3 horizontal line filter */ Coefs[0][0] = 64; Coefs[0][1] = 64; Coefs[0][2] = 64; Coefs[1][0] = 0; Coefs[1][1] = 0; Coefs[1][2] = 0; Coefs[2][0] = -64; Coefs[2][1] = -64; Coefs[2][2] = -64; dqWtRect(oKernel, &tConvRect, Coefs); /* define constants that feed the AP_ADD B operand */ dqSetKVal(oAb00,AB_OP17,0L); dqSetKVal(oAb00,AB_OP18,0L); dqSetKVal(oAb00,AB_OP19,0L); dqSetOpndBaseDT(oAp00,AP_ADD,DQ_OPND_A,DQ_DT_SIGNED); /* shift so that the 8-bit result comes out at DQ_CP15. This shifting must also be accounted for when setting the NMAC coefficients */ dqSpecShift(oAp00, AP_SHIFT8, DQ_SHIFT_ARITHMETIC, 17); dqSpecShift(oAp00, AP_SHIFT, DQ_SHIFT_ARITHMETIC, 7); /* now set the output format to account for the convolution. Horizontal edges are convolved toward -127 and 127. Use the absolute value output so that both edges are driven toward 127. This also shifts the values up one place. */ dqSetOpndBaseDT(oAp00,AP_FORMAT,DQ_OPND_A,DQ_DT_SIGNED); dqSetFormatOp(oAp00,AP_FORMAT,AP_FMT_ABSOLUTE); /* across the cross point switch into AM01 */ dqConnect(oAb00, DQ_CP15, AB_OP01); amSetRcvGateway20MHz(oAm01); oProcDstSurf = dqCreateSameSizeSurf(oAm01, AM_MEM_R8,oProcSrcSurf); dqAttachSurf(oProcDstSurf,AM_RCV); /* create a continuously running pipe, arm and fire it off */ oProcPipe = dqCreatePipe(oProcDstSurf, DQ_TRG_CONTINUOUS); dqArmPipe(oProcPipe, DQ_DSM_PIPE); dqFirePipe(oProcPipe); /*********************** DISPLAY PIPE ********************************/ oDispSrcSurf = dqDupSurf(oProcDstSurf); dqAttachSurf(oDispSrcSurf,AM_XMT); amSetDispGateway40MHz(oAm01); dqSpecXmtExpansion(oAm01,AM_XMT,4,1); dqConnect(oAg00, AG_GREEN, AG_DAC_LUT_SRC); dqConnect(oAg00, AG_DAC_LUT, AG_DAC_SRC); oDispDstSurf = dqCreateSurf(oAg00, AG_DAC,DISPLAYXSIZE,DISPLAYYSIZE); dqAttachSurfGate(oDispDstSurf, AG_RCV); dqSpecRcvShrinkage(oAg00,AG_RCV,4,1); oDispPipe = dqCreatePipe(oDispDstSurf, DQ_TRG_CONTINUOUS); dqArmPipe(oDispPipe, DQ_DSM_PIPE); dqFirePipe(oDispPipe); printf("Hit any key to exit.\n"); fgets(pcUserInpBuf, 80, stdin); dqDisposeSys(oSystem); } /* auxiliary functions to set up the AM gateways to the correct speed */ amSetXmtGateway20MHz(oAmDev) DqIPDev oAmDev; { amSetGateSysClkMult(oAmDev,AM_XMT,2); dqConnect(oAmDev,AM_XMT_OUT,AM_OP3); dqSpecLogic(oAmDev,AM_LOGIC3,0xffffffff,0); dqConnect(oAmDev,AM_SLDN0_T0,AM_OUTPUT0); dqConnect(oAmDev,AM_XMT,AM_XMT_OUT); } amSetRcvGateway20MHz(oAmDev) DqIPDev oAmDev; { dqConnect(oAmDev,AM_SPUP0,AM_INPUT0); dqConnect(oAmDev,AM_INPUT0,AM_OP0); dqSpecLogic(oAmDev,AM_LOGIC4,0,1); dqSpecLogic(oAmDev,AM_LOGIC0,0xffffffff,0); amSetGateSysClkMult(oAmDev,AM_RCV,2); } amSetDispGateway40MHz(oAmDev) DqIPDev oAmDev; { amSetGateSysClkMult(oAmDev,AM_XMT,4); dqConnect(oAmDev,AM_XMT_OUT,AM_OP3); dqSpecLogic(oAmDev,AM_LOGIC3,0xff,0); dqConnect(oAmDev,AM_LOGIC3,AM_OUTPUT0); dqConnect(oAmDev,AM_XMT,AM_XMT_OUT); }