⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c6x1x_edma_mcasp.c

📁 在DSP(DEC6713)上实现了音频的采样与播放!
💻 C
📖 第 1 页 / 共 3 页
字号:
                if (MCASP_FGETH(hMcasp, XSTAT, XCKFAIL)) {
                    MCASP_FSETSH(hMcasp, XSTAT, XCKFAIL, YES);
                    events |= C6X1X_EDMA_MCASP_EVT_XCKFAIL;
                }
                if (MCASP_FGETH(hMcasp, XSTAT, XSYNCERR)) {
                    MCASP_FSETSH(hMcasp, XSTAT, XSYNCERR, YES);
                    events |= C6X1X_EDMA_MCASP_EVT_XSYNCERR;
                }   
                if (MCASP_FGETH(hMcasp, XSTAT, XDMAERR)) {
                    MCASP_FSETH(hMcasp, XSTAT, XDMAERR, 1);
                    events |= C6X1X_EDMA_MCASP_EVT_XDMAERR;
                }   
                /* Clear not registered events here */
                MCASP_RSETH(hMcasp, XSTAT, 0xFFFFFFFF);
            }
            eventReturn = ports[portNbr].evtMask & events;
 
            if (eventReturn) {
                (*ports[portNbr].evtCallback)(eventReturn, portNbr);
            } 
        }   
    }    
}

/*
 * ======== linkPacket ========
 * Links a packet with the EDMA. When called by mdSubmitChan() it is called
 * with all interrupts disabled, but when called by an ISR only the EDMA IRQ
 * is disabled.
 */
static Void linkPacket(ChanHandle chan, IOM_Packet *packet)
{
    EDMA_Handle pramPtr;
    Uns edmaCnt;

    /* Store the packet in the packetList */
    chan->packetList[chan->writeIndex] = packet;

    /* Set up pointer to link PaRAM to write submit job info to */
    pramPtr = chan->pramTbl[chan->writeIndex];
    chan->writeIndex = nextIndex(chan->writeIndex);

    /* Load the buffer pointer into the EDMA */
    if (chan->mode == INPUT) {
        EDMA_RSETH(pramPtr, DST, (Uint32) packet->addr);
    }
    else {
        EDMA_RSETH(pramPtr, SRC, (Uint32) packet->addr);
    }

    /*
     * Load the transfer count (in samples) into the EDMA. Use the ESIZE
     * field of the EDMA job to calculate number of samples.
     */
    edmaCnt = (Uint32)packet->size >> (2 - EDMA_FGETH(pramPtr, OPT, ESIZE));
    EDMA_FSETH(pramPtr, CNT, FRMCNT, (edmaCnt / 
            EDMA_FGETH(pramPtr, CNT, ELECNT) - 1)); 

    /*
     * Link to loop EDMA job upon termination. This way we won't
     * loose the frame sync if the channel is starved.
     */
    EDMA_link(pramPtr, chan->loophEdma);

    /* Disable the EDMA channel to make sure current job doesn't complete */
    EDMA_disableChannel(chan->xferPram);

    /*
     * Link the currently executing job to the new job. This can be
     * either the loop EDMA job or a real data EDMA job.
     */
    EDMA_link(chan->xferPram, pramPtr);

    if (chan->submitCount > 0) {
        /*
         * We need to link the parameter space corresponding to the running
         * job so that if a breakpoint occurs, we know how to recover.
         */
        EDMA_link(chan->prevPramPtr, pramPtr);
    }

    /* Reenable the EDMA channel */
    EDMA_enableChannel(chan->xferPram);

    /* Save the new job for the loop above for next time */
    chan->prevPramPtr = pramPtr;
}

/*
 * ======== mdBindDev ========
 * This function allocates and configures the McASP port specified by devId.
 */
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
    Uns old;
    Int inIrqId;
    int outIrqId;
    int irqId;
    PortHandle port;
    HWI_Attrs hwiAttrs;
    C6X1X_EDMA_MCASP_DevParams *params =
        (C6X1X_EDMA_MCASP_DevParams *) devParams;

    /* This driver must receive a valid devparams */
    if (params == NULL) {
        return (IOM_EBADARGS);
    }

    /* Check the version number */
    if (params->versionId != C6X1X_EDMA_MCASP_VERSION_1){
        /* Unsupported version */
        return(IOM_EBADARGS);
    }

    /* Get the device parameters of the specified port */
    port = &ports[devid];

    /* Mark the port as in use */
    old = ATM_setu(&(port->inUse), TRUE);

    /* Check if the port was already bound */
    if (old) {
        return (IOM_EALLOC);
    }

    /* Map the supplied IRQ to the EDMA event */
    if (params->irqId > 0 ) {
        irqId = params->irqId;
    }
    else {
        irqId = IRQEDMA;
    }
    IRQ_map(IRQ_EVT_EDMAINT, irqId);

    hwiAttrs.intrMask = params->edmaIntrMask;
    hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
    hwiAttrs.arg = NULL;

    /* Plug the EDMA dispatcher into the HWI dispatcher */
    HWI_dispatchPlug(irqId, (Fxn)EDMA_intDispatcher, -1, &hwiAttrs);
   
    /* Set the McASP high frequency sample rate generator */
    /* Set the McASP sample rate generator */
    /* Set the McASP frame sync generator */
    port->enableHclkg = params->enableHclkg;
    port->enableClkg = params->enableClkg;
    port->enableFsyncg = params->enableFsyncg;

    /* True if buffers are in external memory */
    port->cacheCalls = params->cacheCalls;

    /* Store the devid */
    port->devId = devid;

    /* No channel create yet */
    port->chanCreated = 0;

    /* Open and reset the McASP */
    port->hMcasp = MCASP_open(devid, MCASP_OPEN_RESET);

    if (port->hMcasp == INV) {
        return (IOM_EALLOC);
    }

    /* Configure the McASP with the supplied configuration */
    MCASP_config(port->hMcasp, params->mcaspCfgPtr);

    if (params->evtCallback != NULL) {
        /* register the events */
        port->evtCallback = params->evtCallback->evtFxn;
        port->evtMask = params->evtCallback->evtMask;
 
        if (params->inEvtIrqId > 0) {
            inIrqId = params->inEvtIrqId;
        }
        else {
            inIrqId = IRQEVTINPUT;
        } 

        if (params->outEvtIrqId > 0) {
            outIrqId = params->outEvtIrqId;
        }
        else {
            outIrqId = IRQEVTOUTPUT;
        } 

        IRQ_map(MCASP_getXmtEventId(port->hMcasp), outIrqId);
        IRQ_map(MCASP_getRcvEventId(port->hMcasp), inIrqId); 

        hwiAttrs.intrMask = params->inEvtIntrMask;
        hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
        hwiAttrs.arg = INPUT;
        HWI_dispatchPlug(inIrqId, (Fxn)isrEvent, -1, &hwiAttrs);

        hwiAttrs.intrMask = params->outEvtIntrMask;
        hwiAttrs.ccMask = IRQ_CCMASK_NONE; /* the default value */
        hwiAttrs.arg = OUTPUT;
        HWI_dispatchPlug(outIrqId, (Fxn)isrEvent, -1, &hwiAttrs);
    } 
    else {
        port->evtCallback = NULL;
    }

    /* set 0xe for debug, real value should be 0 */
    loopSrcBuf = 0;
    loopDstBuf = 0; 

    /* Return the device handle and a status code for success */
    *devp = port;
    return (IOM_COMPLETED);
}

/*
 * ======== mdCreateChan ========
 * This function creates and configures a device channel.
 */
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
                        Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
    PortHandle port = (PortHandle) devp;
    C6X1X_EDMA_MCASP_ChanParams *params =
        (C6X1X_EDMA_MCASP_ChanParams *) chanParams;
    ChanHandle chan;
    Uns old;
    Uns esize;
    Uns cnt;
    Uns fs;
    Uns elerld;
    Uns mcaspAddr;
    Int edmaChanEvent;
    Int i;
#if ENABLELOOPINTR
    Int loopTcc;
#endif

    /*
     * Configuration structure for the loop EDMA job. If the McASP
     * is left to free running, this loop job is running when there is
     * no data to transfer. This is useful if the McASP is externally
     * clocked.  If the driver is starved or if an emulation halt
     * (breakpoint) occurs, the frame sync will still be correct when
     * the driver continues transmitting data.
     */
    EDMA_Config loopEdmaCfg = {
        EDMA_FMKS(OPT, PRI, HIGH)           |
        EDMA_FMKS(OPT, ESIZE, 32BIT)        |
        EDMA_FMKS(OPT, 2DS, NO)             |
        EDMA_FMKS(OPT, SUM, NONE)           |
        EDMA_FMKS(OPT, 2DD, NO)             |
        EDMA_FMKS(OPT, DUM, NONE)           |
        EDMA_FMKS(OPT, TCINT, NO)           |
        EDMA_FMKS(OPT, TCC, DEFAULT)        |
        EDMA_FMKS(OPT, LINK, YES)           |
        EDMA_FMKS(OPT, FS, NO),

        EDMA_FMK (SRC, SRC, NULL),

        EDMA_FMK (CNT, FRMCNT, 0)           |
        EDMA_FMK (CNT, ELECNT, 0),

        EDMA_FMKS(IDX, FRMIDX, OF(0))       |
        EDMA_FMKS(IDX, ELEIDX, OF(0)),

        EDMA_FMK (DST, DST, NULL),

        EDMA_FMK (RLD, ELERLD, 0)           |
        EDMA_FMK (RLD, LINK, NULL)
    };


    /* This driver needs a valid channel parameter structure passed */
    if (params == NULL) {
        return (IOM_EBADARGS);
    }

    /* Use own indexes since IOM mode is a bit mask and not an index */
    if (mode == IOM_INPUT) {
        chan = &port->chans[INPUT];
        chan->mode = INPUT;
    }
    else {
        chan = &port->chans[OUTPUT];
        chan->mode = OUTPUT;
    }

    /* Mark the channel as used */
    old = ATM_setu(&(chan->inUse), TRUE);

    /* Make sure the channel wasn't already created */
    if (old) {
        return (IOM_EALLOC);
    }

    /* Initialise the channel structure */
    chan->cbFxn = cbFxn;
    chan->cbArg = cbArg;
    chan->port = port;
    chan->writeIndex = 0;
    chan->readIndex = 0;
    chan->submitCount = 0;
    chan->flushPacket = NULL;
    chan->abortPacket = NULL;

    /* Initialize the packet queue */
    QUE_new(&chan->packetQueue);

    /*
     * Set the number of elements (corresponding to number of McASP TDM
     * channels) used in the Loop job to preserve the frame sync.
     * FRMCNT should be (num of TDM slots - 1);
     */
    cnt = params->tdmChans - 1;
    EDMA_FSETA(&loopEdmaCfg.cnt, CNT, FRMCNT, cnt);
    EDMA_FSETA(&loopEdmaCfg.cnt, CNT, ELECNT, params->edmaCfgPtr->cnt);

    /* Use the same sample size in the Loop job as in normal jobs */
    esize = EDMA_FGETA(&params->edmaCfgPtr->opt, OPT, ESIZE);
    EDMA_FSETA(&loopEdmaCfg.opt, OPT, ESIZE, esize);

    /* Use  the same FS info as in the normal job */
    fs = EDMA_FGETA(&params->edmaCfgPtr->opt, OPT, FS); 
    EDMA_FSETA(&loopEdmaCfg.opt, OPT, FS, fs);

    /* Use  the same ELERLD info as in the normal job */
    elerld = EDMA_FGETA(&params->edmaCfgPtr->rld, RLD, ELERLD); 
    EDMA_FSETA(&loopEdmaCfg.rld, RLD, ELERLD, elerld); 

    /* Allocate a TCC for the EDMA */
    chan->tcc = EDMA_intAlloc(-1);
    /* If tcc > 15 we abort. */
    if (chan->tcc == -1 || chan->tcc > 15) {
        chanCleanUp(chan, SETFALSE);
        return (IOM_EALLOC);
    }

#if ENABLELOOPINTR
    loopTcc = EDMA_intAlloc(-1);
    /* If tcc > 15 we abort. */
    if (loopTcc == -1 || loopTcc > 15) {
        EDMA_intFree(loopTcc);
        chanCleanUp(chan, FREETCC);
        return (IOM_EALLOC);
    }
#endif

    /* Allocate an EDMA PaRAM for the Loop EDMA job. */
    chan->loophEdma = EDMA_allocTable(-1);

    if (chan->loophEdma == EDMA_HINV) {
        chanCleanUp(chan, FREETCC);
        return (IOM_EALLOC);
    }

    /*
     * Allocate EDMA PaRAM link area based on max number of
     * submits possible.
     */
    if (EDMA_allocTableEx(MAXLINKCNT, chan->pramTbl) != MAXLINKCNT) {
        chanCleanUp(chan, FREETABLE);
        return (IOM_EALLOC);
    }

    /* workaround for big endian problem in McASP */
    if (chan->mode == INPUT) {
        mcaspAddr = MCASP_getRbufAddr(port->hMcasp);
    }
    else {
        mcaspAddr = MCASP_getXbufAddr(port->hMcasp);
    }

#ifdef _BIG_ENDIAN
    if (esize == EDMA_OPT_ESIZE_8BIT) {
        mcaspAddr += 3;
    }
    else if (esize == EDMA_OPT_ESIZE_16BIT) {
        mcaspAddr += 2;
    }
#endif

    if (chan->mode == INPUT) {
        
        /* Put input specific parameters in the Loop EDMA config */
        EDMA_RSETA(&loopEdmaCfg.src, SRC, mcaspAddr);
        EDMA_RSETA(&loopEdmaCfg.dst, DST, (Uint32) &loopDstBuf);

        EDMA_RSETA(&params->edmaCfgPtr->src, SRC, mcaspAddr);
        /* Register our isrInput with the EDMA dispatcher */
        EDMA_intHook(chan->tcc, &isrInput);
    }
    else {     
        
        /* Put output specific parameters in the Loop EDMA config */
        EDMA_RSETA(&loopEdmaCfg.src, SRC, (Uint32) &loopSrcBuf);
        EDMA_RSETA(&loopEdmaCfg.dst, DST, mcaspAddr);

        EDMA_RSETA(&params->edmaCfgPtr->dst, DST, mcaspAddr);
        /* Register our isrOutput with the EDMA dispatcher */
        EDMA_intHook(chan->tcc, &isrOutput);
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -