Hello everyone, this is my first post on e2e forums so I hope it is not much of a bother.
I am using TMS320C6424 EVM and trying to receive a stream of messages in a wav file by using the AIC33 and a ping pong edma arrangement. There is a noticeable amount of dropped messages ( 1% - 6% ) when using the whole program.A summary of the relevent settings:
AIC FS = 48 KHz, using FS/6 (8 KHz)
EDMA reads from McBSP_DRR into a ping pong buffer while the processing code runs on the other buffer, semaphores prevent the processing code from accessing a non-full buffer
EDMA is triggered by REVT1
In order to isolate the issue I tested the system from the EDMA onwards by using the following configuration:
EDMA reads from a hard-coded array that contains the same wav file data and writes in the same ping pong buffers, EDMA is triggered manually in every ISR until the buffer is full. a-sync is used and both intermediate and final transfer complete inturrupts were enabled. The end of file is detected by a counter that counts how many ISR's were called, when the buffer is full, the edma stops until the processing on that buffer is finished at which time the processing code triggers the EDMA again.
this time all the packets were decoded successfully.
I then tried the other side and used a simple code to write in the McBSP DXR whatever it finds in the DRR and then recorded the received file in the computer; decoding this file also didn't result in any packets lost.
I suspected that there might be a timing issue between the EDMA and the McBSP so I went back to the edma code that reads from a hardcoded array and changed the edma triggering back to an event driven configuration as opposed to the manual triggering I used for the previous test. I created another channel that transfers the DRR to a dummy variable and its ISR triggers the transfer from the hard-coded array to the ping pong buffer. The amount of dropped packets decreased to less than 0.6 %. but the drop still exists.
I am now wondering where exactly does the packets loss occur? and how can I improve it
attached is the code for the edma for the intended usage (reading from DRR and writing into the buffer).
// ================================ EDMA.C ===================================== // // Authors: Scott Specker and Eric Wilbur (Technical Training Organization) // Date: 02/16/09 // Rev: 1.4 // Target: DM6437 EVM // BIOS ver: 5.31 // LLD version: edma3_lld_01_06_00_01 // Name: EDMA3 LLD Example7 (Audio Pass-through example with linking/sorting) // // To download the latest LLD release, go to the following URL: // https://www-a.ti.com/downloads/sds_support/TargetContent/psp/edma3_lld/index.html // // Abstract: The purpose of this example is to provide users with a simple example of // using the Low Level Driver (LLD) libraries to program and execute transfers // using the EDMA3 peripheral. // // Also generates an EDMA interrupt that is sent to the CPU. // // This example uses event triggering from the RCV and XMT buffers in // the McBSP. // // NEW *** This is a full audio pass through example using the LLD to process // the incoming audio data. The mcbsp init was stolen from a previous // 4-day 6455 workshop example. We also needed the tasks.c file to // process the buffers (memcopy) and pend on RCV/XMT semaphores. // // API: In effect, we have created a small API in edma.c and edma.h that // encapsulates using the LLD functions. These edma_xxx functions allowed us // to simplify our example program (in main.c) and also let us partition the // LLD code in an easily digestable manner. // // The following two functions initialize the EDMA3 and channel resources // - edma_config(); // - edma_createChan(); // // The following three functions execute and verify completion of the transfer // - edma_start(); // - edma_check(); // - edma_wait(); // // The following two functions free up the channel and EDMA3 resources // - edma_deleteChan(); // - edma_release(); // // Our API creates a typedef (edma_object_t) in edma.h that allows the // calling program to define and use the following elements: // - hEdma: handle to the EDMA3 resources for this API // - iChannel: channel Id number (0-63 or EDMA3_DRV_CHANNEL_ANY) // - iTcc: transfer completion code (0-63 or EDMA3_DRV_TCC_ANY) // // This example acts very much like a memcpy() - if this is all the // functionality you need, you may be better served by using TI's ACPY // library. // // This example is a starting point which we will add more capability to // such as generating an EDMA3 interrupt to the CPU and syncing // transfers to events from a peripheral (e.g. McBSP). // // Usage: The following libraries are required in your project: // - edma3_drv_bios.lib // - edma3_drv_bios_sample.lib // - edma3_rm_bios.lib // // These libraries are located in the following directories respectively: // - [lld_root]\packages\ti\sdo\edma3\drv\lib\Debug (can also use \Release) // - [lld_root]\packages\ti\sdo\edma3\drv\sample\lib\c6455\Debug (platform-specific .lib) // - [lld_root]\packages\ti\sdo\edma3\rm\lib\c6455\Debug (platform-specific) // where [lld_root] is the installation location of the LLD driver. // // The following header files must be included with your edma code for these // libraries to work properly: // - <edma3_drv.h>: LLD Driver header file // - <bios_edma3_drv_sample.h>: OS-specific and device-specific header file // All other header files used are already included in the above header files. // (Note, you will find them #included below these comments in this file; if you are // using our framework - i.e. this file - then we've already done this work for you.) // // For the header files, you will need to specify the include search paths (-i). // You can accomplish this by using CCS (Project->Build Options->Compiler->Preprocessor: // Add the following paths: // - [lld_root]\packages\ti\sdo\edma3\rm // - [lld_root]\packages\ti\sdo\edma3\drv // - [lld_root]C:\edma3_lld_1_05_00\packages\ti\sdo\edma3\drv\sample // - [lld_root]\packages (this path is required since some of the #includes // found in edma3_drv.h are referenced from "packages") // // LLD is OS-agnostic and supports the following operating systems: // - DSP/BIOS // - PROS // This is a BIOS project, hence the use of "bios" in the library names above. As you // can see, the second two libraries are platform-specific (i.e. C6455). The first // library (edma3_drv_bios.lib) encapsulates the "RM" (resource management) layer // underneath. // // The user must provide a semaphore to the LLD to allow it to manage resources. // While the LLD provides a function to create this semaphore, we thought it was // easier to create it statically in the .tcf file (OsSem) and pass it to the LLD. // The LLD library requires a counting semaphore with an initial count of 1. // (Note: because semaphores are OS-specific, the OsSemCreate function must be // tuned for your OS - thus we thought it was easier to do directly in BIOS). // // // Int Gen: There are several steps required to get interrupts to work properly: // // For CPU: 1. Turn on the proper CPU IER bit (done in main.c, CPU-specific) // 2. Turn on global interrupts (GIE) - already done for us by DSP/BIOS when // we return from main() in main.c. // 3. Create an HWI (we used HWI_INT5) in the .tcf file. You need to point this // HWI (i.e. the function to run) to the EDMA interrupt dispatcher which is // _lisrEdma3ComplHandler0. This handler checks all of the IPR bits and if it // finds one that is set, it calls the corresponding callback function you // sent via the _requestChannel API (see tccCb = &edma_isr). This handler // also clears the specific IPR bit that was set. AND don't forget to set the // interrupt selection number corresponding to the interrupt you are tying to // respong to. In our case, we are using the Region 1 interrupt from the EDMA // which just so happens to be selection number 72. You can find a table of // these in the datasheet (SPRS276, Section 7.5, about page 119). // 4. Create an ISR (such as edma_isr located at the bottom of this file). We // simply put a LOG_printf() there for debug purposes. // For EDMA: 5. The EDMA IER bit is set during the _requestChannel API call. So, the user // does NOT need to write to the IESR manually to set the corrersponding // IER bit for the TCC. // 6. In the Options register, TCINTEN must be enabled (however it already was // enabled in our previous example - so no changes were made here). // 7. Register a callack function (edma_isr) to be used by _requestChannel(). This // function will be placed in a table used by the EDMA3 Completion Handler 0. // See tccCb = &edma_isr in the edma_createChan() function. // 8. In edmaTsk (in main.c), with the 2 second timer interrupt, we were deleting // the channel resources before the EDMA completed its job. So, when the EDMA // finished the transfer, the EDMA ISR wasn't configured any longer. So, we added // a DSP/BIOS semaphore (SEM) to edmaTsk (in main.c) to PEND (i.e. wait) until // the EDMA had fully completed its job. A SEM_post was added to our ISR to tell // edmaTsk that the transfer was finished. This signaling between the ISR and // edmaTsk fixed the problem. // // // Evt Sync: To get event synchronization to work, we added the following to this example: // 1. In the .tcf file - Clock Manager, we set the period to 2 seconds on Timer 0. // When Timer 0 reaches zero, it will send an event trigger to the EDMA and set // the corresponding ER (Event Register) bit. // 2. We can still use EDMA3_TCC_ANY (see main.c), but we changed the channel // enumeration to channel 1 (see main.c). Reference the EDMA User Guide // (SPRU966, about page 43) to see the list of events tied to various channels. // Timer 0 LO event is tied to channel 1. // 3. In the edma_start() function, notice the change to _enableTransfer // paramaters. We changed EDMA3_DRV_TRIG_MODE_MANUAL to // EDMA3_DRV_TRIG_MODE_EVENT. This will set the EER bit corresponding to the // chosen channel (in our case, it is channel 1 which is passed via the EdmaObj // from main to edma_start()). // // A-sync: 1. In edma_creatChan(), the call to _setTransferParams uses A-sync vs. AB-sync // // Intermediate // Interrupts: 2. A new _setOptField was added to turn on intermediate interrupts. This // will provide 14 intermediate interrupts and plus the two final interrupts // enabled by TCINTEN (which we had before). The log of this activity will // be logged in the LOG_printf() in edma_isr() which counts the number // of times the interrupt occurred. // // Link: We needed to do the following to request another PaRAM set (PSET) and link iChannel // (our active channel) to the reload (link) channel iReload: // // 1. Do another _requestChannel for iReload PSET // 2. Copy the PaRAM set values from iChannel to iReload // 3. Modify the Src/Dst addresses for iReload (to point to our second set of buffers) // 4. Link iChannel to iReload using _linkChannel() // // Note: The LLD Driver allocates physical PaRAM sets (PSETs) in numerical order starting // at PSET 0 and counting up. So, iChannel is PHYSICALLY using PSET 0 and iReload // is using PHYSICAL PSET 1. This can be a nightmare to debug if you don't this // important information. In the future, when we have two active channels (RCV and // XMT) and 4 reload PSETs, the LLD Driver will allocate these to the first 6 // PSETs (0-5). That is why we used the _getPaRAM API so that we could look at // both the iChannel and iReload PaRAM sets - abstracting us from the actual // physical PSETs used by the driver. // // Channel // Sorting: The following changes were made to get channel sorting to work: // 1. ACNT remains the same (2) // 2. BCNT is now 2 instead of BUFFSIZE. // 3. SRC BIDX is still 2 bytes // 4. SRC CIDX is 2 bytes. // 5. CCNT is now 8 instead of 1. This will move 8 values for the first transfer // and then 8 more after linking occurs. // 6. BCNTRLD must now be modified because CCNT > 1. BCNTRLD = 2. // 7. DST BIDX must be set to BUFFSIZE*2 bytes so after the first value is // transferred to SrcBufEven, it can index to the first value in DstBufOdd. // 8. DST CIDX will allow us to move backwards from DstBufOdd to the next value // in DstBufEven - about 2-(BUFFSIZE-2) bytes. // // These values were changed in both iChannel and therefore iReload as well. // // Note: when you halt the processor and look at the values (View-Memory), type in // SrcBuf1 and use "Hex 16-bit TI Style" to view the values. It looks better // that way. // // *************************** NEW TO THIS EXAMPLE7 *********************************** // // Audio: Many items were added and modified to make this example work: // 1. The sync event is now coming from the Rcv/Xmt McBSP vs. a timer event. In main.c // this is accomplished by choosing the proper channels (REVT1, XEVT1) which are // hardwired to the ER bits in the EDMA // 2. For a sync'd ping/pong transfer, we need 6 PSETs. Two are our active channels // (one for RCV and one for XMT). The RCV side uses the McBSP DRR as the source // and gBufferRcv as the destination. The XMT side uses gBufferXmt as the source // and the McBSP DXR register as its destination. The other 4 PSETs are used for // linking ping and pong. The active channels are set as "ping" and are linked to // the pong reload PSETs. The pong reload PSET is linked back to ping. Hence, // we have two active channels and 4 reload PSETs. // 3. Channel sorting is also occurring. The incoming data from the McBSP comes into // the DRR as LRLRLRLR samples. We channel sort these into left and right buffers // within the ping and pong buffers. This is accomplished on the incoming data // (into gBufferRcv) and outgoing data (from gBufferXmt) by setting the proper // index values as shown in the code below. // 4. Because this system runs forever, we will never require the _deleteChan and // _release functions in this example application. // 5. You could possibly improve this system in a couple different ways: // a. By checking error conditions returned from the LLD functions and handling // them appropriately. // b. While outside the scope of this example, you could use other system control // inputs to signal an exit from audio processing, using the _deleteChan and // _release functions to free up the EDMA resources. // // *************************** END OF NEW TO THIS EXAMPLE7 *********************************** // // Diagrams: This simple diagram may help provide some context to how the LLD driver (DRV) // and Resource Manager (RM) work together. The user's responsibility is to // use the DRV APIs - the RM is accessed solely by DRV. Also notice that if you // are using ACPY3 & DMAN framework, it actually uses the LLD's Resource Manager. // // ------------------------ // ------- | Framework Components | // | APP | | DMAN, ACPY | // ------- ------------------------ // | | // | | // -------------------- ------------------------- // | LLD Driver (DRV) | --> | Resource Manager (RM) | // -------------------- ------------------------- // | // | // ------------------ // | EDMA3 Hardware | // ------------------ // // PSP is the Platform Support Package (peripheral drivers) supplied by TI: // It includes the LLD libraries among other libraries // // Build // Warnings: When we built this project, we saw several warnings that edma3Result // was declared but never used. We did not write in the error-checking code // to check the results returned from some functions. You may add that code // if so desired. In Build Options -> Compiler -> Diagnostics, we figured out // which warning id number it was by using -pden, then suppressed that warning // id (552) using -pds552. // // ================================================================================== // ============================== INCLUDES ===================================== #include "main.h" // contains BUFFSIZE, PSET_EDMA and externs for Src/Dst arrays #include "edma.h" // includes prototypes for all edma functions #include <edma3_drv.h> // LLD Driver header file #include <bios_edma3_drv_sample.h> // OS-specific and device-specific header file //#include <src\edma3_rl_cc.h> //needed for the EDMA3_CCRL_RegsOvly global (for debug) #include <edma3_rl_cc.h> //needed for the EDMA3_CCRL_RegsOvly global (for debug) // ============================== PROTOTYPES ===================================== void edma_rcv_isr(); void edma_xmt_isr(); // =============================== GLOBALS ===================================== // used for EDMA3_DRV_create() API, edma3InstanceId also used in EDMA3_DRV_delete() static unsigned int edma3InstanceId = 0; //only one hardware EDMA3 instance // declare sample Params for 6455 - this list of parameters is DEVICE SPECIFIC extern EDMA3_DRV_GblConfigParams sampleEdma3GblCfgParams; // External Instance Specific Configuration Structure - resources owned by region 1 (PARAM sets, channels, TCCs, etc.) // DEVICE-SPECIFIC extern EDMA3_DRV_InstanceInitConfig sampleInstInitConfig; // Used for debug purposes and hence we kept it global. This pointer will point to the // entire set of the CC Regs (like the EDMA's IPR and IER regs) so you can view them // while debugging. Simply add CCRegsPtr to a watch window. We also use this pointer to // write to the EDMA IER register via the EDMA IESR register in edma_createChan(). EDMA3_CCRL_RegsOvly CCRegsPtr; // ============================ EDMA CONFIG =================================== // // This function will: // - create an instance (edma3InstanceId) for each EDMA3 hardware peripheral // - provide a handle (hEdma) to the user instance of the EDMA mdoule // // DRV_create requires a globalConfig structure which contains the hardware resources // available for this device (we used sampleEdma3GblCfgParams to accomplish this). // // DRV_open requires the initCfg structure to initialize the Driver Instance. // // Note: this function CLEARS all ER (Event Register) bits. So, if you are using // sync'd transfers, your sync event must occur AFTER this function is // finished - otherwise, it may not work properly // =================================================================================== void edma_config(edma_object_t *EdmaObj) { // set initial value of edma3Result which can be used for error-checking (we opted NOT to put // error-checking in this example, but users could improve this code by doing so). EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; // set global config to defaults in sample Params (located in bios_edma3_drv_sample_C6455_cfg.c) EDMA3_DRV_GblConfigParams *globalConfig = &sampleEdma3GblCfgParams; // used in DRV_create() function to specify master/slave EDMA3_RM_MiscParam miscParam; // used for EDMA3_DRV_open() API and initCfg structure, defined in <edma3_drv.h> EDMA3_DRV_InitConfig initCfg; // initial values for C6455 EDMA hardware - used to pass into the _open call via initCfg // the values are actually located in bios_edma3_drv_sample_C6455_cfg.c EDMA3_DRV_InstanceInitConfig *instanceConfig = &sampleInstInitConfig; // Declare Config structure used to initialize the Driver Instance (needed by DRV_open) initCfg.isMaster = TRUE; // we are a master, not a slave on this device initCfg.regionId = (EDMA3_RM_RegionId)1u; // user must specify region (LLD/DRV does not support "global" region) initCfg.drvSemHandle = &OsSem; // OsSem added statically in the .tcf file with an initial count of 1 initCfg.drvInstInitConfig = instanceConfig; // device-specific configuration - resources owned by region 1 initCfg.gblerrCb = NULL; // callback function to catch channel controller errors such as TCC error, queue threshold exceeded, etc. initCfg.gblerrData = NULL; // any data required by the error callback function // ARM + DSP, specify who is the master, single-chip C6455 = use FALSE miscParam.isSlave = FALSE; // EDMA3 Driver Create (called only once for each EDMA3 hardware instance) edma3Result = EDMA3_DRV_create(edma3InstanceId, globalConfig, (void *)&miscParam); // Open user instance to EDMA Module (hEdma) EdmaObj->hEdma = EDMA3_DRV_open (edma3InstanceId, (void *) &initCfg, &edma3Result); // The following is used for debug and programming purposes - to be able to access the CC Regs. // To use, simply add CCRegsPtr to your watch window (to view the EDMA registers // such as IPR, IER, etc.). This pointer is set to the TOP of the CC Registers - the // location of this pointer (0x02A00000) is found in the Global Config Params for C6455. // This pointer is also used in edma_createChan to set the EDMA's IER bit to enable // EDMA interrupts after the corresponding IPR bit (TCC) is set when the transfer completes. CCRegsPtr = sampleEdma3GblCfgParams.globalRegs; } // ============================ EDMA CREATE CHANNEL ============================ // // This function will: // - allocate all the necessary channel resources and assign them to a channel Id // - initialize the allocated PARAM registers (like ACNT, BCNT, IDXs, etc.) // - set the Options register to all default values (done by _requestChannel automatically) // - EDMA IER register bit is enabled by _requestChannel for each channel used // - allocates another channel for reload and links iChannel to iReload // - sets the counts and indexes to the proper amounts to perform channel sorting. // - this function is called TWICE (once for RCV and once for XMT). As is shown below, // we perform 6 _requestChannels - two for the active RCV/XMT channels and 4 others to // allow us to link to Rcv (ping, pong) and Xmt (ping, pong). // // The following are the default values that are used for the OPT register and LINK // fields. If you desire to overide any of these defaults, copy this code and make the // necessary modifications (as you can see we did below for the TCINTEN bit and ITCINTEN): // // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_ITCCHEN, EDMA3_DRV_ITCCHEN_DIS); //Intermediate Chaining DISABLED - default is DIS if not called // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_TCCHEN, EDMA3_DRV_TCCHEN_DIS); //Chaining DISABLE - default is DIS if not called // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_ITCINTEN, EDMA3_DRV_ITCINTEN_DIS); //Intermediate interrupt enable DISABLED - default is DIS if not called // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_TCINTEN, EDMA3_DRV_TCINTEN_DIS); //Interrupt enable DISABLED - default is DIS if not called // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_TCC, 0u); //already set in EDMA3_DRV_requestChannel //TCC value - arbitrary // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_STATIC, EDMA3_DRV_STATIC_DIS); //FIFO mode not used - so, we set it to zero - default is DIS if not called // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_SYNCDIM, EDMA3_DRV_SYNC_AB); //Sync set to AB (we want an AB transfer after the manual start - not needed - already set to AB // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_SAM, EDMA3_DRV_ADDR_MODE_INCR); //Src Addr Mode = INCR - already set in EDMA3_DRV_setSrc/DstParams //Address mode is INCR (not FIFO) // EDMA3_DRV_setOptField (hEdma,iChannel, EDMA3_DRV_OPT_FIELD_DAM, EDMA3_DRV_ADDR_MODE_INCR); //Dst Addr Mode = INCR - already set in EDMA3_DRV_setSrc/DstParams // // EDMA3_DRV_linkChannel (hEdma, iChannel, 0xFFFFu); //Set link field to FFFF - no linking - this is the default if this API is not called // // =================================================================================== void edma_createChan(edma_object_t *EdmaObj, int16_t *Src, int16_t *Dst) { // return value for some driver calls so they can return an error (we don't check for errors in this example) EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; // used for debug purposes in EDMA3_DRV_getPaRAM() - also can set one PSET equal to another (handy) EDMA3_DRV_PaRAMRegs channelParam; // ACTIVE logical channel EDMA3_DRV_PaRAMRegs pingParam; // Ping Reload PSET (set to same values as initial channelParam) EDMA3_DRV_PaRAMRegs pongParam; // Pong Reload PSET // Queue (0-3) that you want your channel tied to (Q1 on C6455 is the only queue tied to McBSP // (see SCR connnection matrix) - so if you choose any queue other than "1", this app will NOT work EDMA3_RM_EventQueue eventQ = 1; EDMA3_RM_TccCallback tccCbRcv = &edma_rcv_isr; // callback function from EDMA handler (see HWI_INT5 in .tcf file) EDMA3_RM_TccCallback tccCbXmt = &edma_xmt_isr; // callback function from EDMA handler (see HWI_INT5 in .tcf file) // get channel for transfer - iChannel - for either Rcv or Xmt if (EdmaObj->iChannel == EDMA_HW_EVENT_REVT1) { // RECEIVE (input) channel // get iChannel for Rcv and set queue and EDMA dispatcher callback function edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iChannel, &EdmaObj->iTcc, eventQ, tccCbRcv, NULL); // set Src address for Rcv (i.e. DRR) and set SAM/DAM to INCR mode //EDMA3_DRV_setSrcParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (Src), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); EDMA3_DRV_setSrcParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (0x01D00800), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); // set Dst address for Rcv (i.e. gBufferRcv[0]) and set SAM/DAM to INCR mode EDMA3_DRV_setDestParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (Dst), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); // set Rcv channel indexes (SRC BIDX/CIDX are zero because DRR is a fixed location) EDMA3_DRV_setSrcIndex(EdmaObj->hEdma, EdmaObj->iChannel, 0, 0); // set Dst channel indexes (DST BIDX increments by BUFFSIZE bytes, DST CIDX is set to bump the // address pointer back to sort L/R channels of audio // not valid, not channel sorting is used EDMA3_DRV_setDestIndex(EdmaObj->hEdma, EdmaObj->iChannel, 0, 2); // DST BIDX = 0 means no offset will occur after gettnig ACNT bytes from DRR of the McBSP // that means, Both left and roght samples (2bytes each) will be written in the same // location at the destination buffer // DST CIDX = 2 means after reading BCNT times, ACNT bytes each // offset the dst by 2 from the last known address EDMA3_DRV_setTransferParams(EdmaObj->hEdma, EdmaObj->iChannel, 2, 2, BUFFSIZE, 2, EDMA3_DRV_SYNC_A); } else { // TRANSMIT (output) channel // get iChannel for Xmt and set queue and EDMA dispatcher callback function edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iChannel, &EdmaObj->iTcc, eventQ, tccCbXmt, NULL); // set Src address for Xmt (i.e. gBufferXmt[0]) and set SAM/DAM to INCR mode EDMA3_DRV_setSrcParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (Src), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); // set Dst address for Xmt (i.e. DXR) and set SAM/DAM to INCR mode //EDMA3_DRV_setDestParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (Dst), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); EDMA3_DRV_setDestParams (EdmaObj->hEdma, EdmaObj->iChannel, (unsigned int) (0x01D00804), EDMA3_DRV_ADDR_MODE_INCR, EDMA3_DRV_W8BIT); // set Xmt channel Src indexes (SRC BIDX increments by BUFFSIZE bytes, SRC CIDX is set to bump the // address pointer back to sort L/R channels of audio) // this comment in no longer valid EDMA3_DRV_setSrcIndex(EdmaObj->hEdma, EdmaObj->iChannel, 0, 2); // SRC BIDX = 0 means no offset will occur after sending ACNT bytes to DXR of the McBSP // that means, the same sample (2bytes) will be send out again // to the DXR but this time as a Left sample // SRC CIDX = 2 means after sending out BCNT times, ACNT bytes each // offset the src by 2 from the last known address // set Xmt channel Dst indexes (DST BIDX/CIDX are zero because DXR is a fixed location) EDMA3_DRV_setDestIndex(EdmaObj->hEdma, EdmaObj->iChannel, 0, 0); EDMA3_DRV_setTransferParams(EdmaObj->hEdma, EdmaObj->iChannel, 2, 2, BUFFSIZE_TX, 2, EDMA3_DRV_SYNC_A); } // Regardless of whether we are setting up RCV or XMT, these values are the same for both. // Because this example requires A-sync, notice the parameter EDMA3_DRV_SYNC_A was used vs. _AB // ACNT=2, BCNT=2, CCNT=BUFFSIZE, BCNTRLD=2, SYNC=A //********** //EDMA3_DRV_setTransferParams(EdmaObj->hEdma, EdmaObj->iChannel, 2, 2, BUFFSIZE, 2, EDMA3_DRV_SYNC_A); // Interrupt enable ENABLED - FINAL interrupt after transfer complete is enabled EDMA3_DRV_setOptField (EdmaObj->hEdma,EdmaObj->iChannel, EDMA3_DRV_OPT_FIELD_TCINTEN, EDMA3_DRV_TCINTEN_EN); // Get pingParam values so we can set pong = ping and change a few PSET values for pong EDMA3_DRV_getPaRAM(EdmaObj->hEdma, EdmaObj->iChannel, &pingParam); // set Pong = Ping (then shortly we will change a few of the pong PSET values) pongParam = pingParam; // if we're setting up Rcv or Xmt, pongParam needs to be modified to set the src/dest // addresses appropriately. Must also do two _requestChannels for the reload PSETs if (EdmaObj->iChannel == EDMA_HW_EVENT_REVT1) { pongParam.destAddr = (unsigned int)&gBufferRcv[1]; // gBufferRcv[1] (half way thru buffer) edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iReloadPing, &EdmaObj->iTcc, eventQ, tccCbRcv, NULL); edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iReloadPong, &EdmaObj->iTcc, eventQ, tccCbRcv, NULL); } else { pongParam.srcAddr = (unsigned int)&gBufferXmt[1]; // gBufferXmt[1] (half way thru buffer) edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iReloadPing, &EdmaObj->iTcc, eventQ, tccCbXmt, NULL); edma3Result = EDMA3_DRV_requestChannel (EdmaObj->hEdma, &EdmaObj->iReloadPong, &EdmaObj->iTcc, eventQ, tccCbXmt, NULL); } // set iReload equal to iChannel PARAM values EDMA3_DRV_setPaRAM (EdmaObj->hEdma, EdmaObj->iReloadPing, &pingParam); EDMA3_DRV_setPaRAM (EdmaObj->hEdma, EdmaObj->iReloadPong, &pongParam); // link channels edma3Result = EDMA3_DRV_linkChannel (EdmaObj->hEdma, EdmaObj->iChannel, EdmaObj->iReloadPong); edma3Result = EDMA3_DRV_linkChannel (EdmaObj->hEdma, EdmaObj->iReloadPong, EdmaObj->iReloadPing); edma3Result = EDMA3_DRV_linkChannel (EdmaObj->hEdma, EdmaObj->iReloadPing, EdmaObj->iReloadPong); // this is not required, but for debug purposes we are reading back currentParam so that // we can view that the LINK field changed in the iChannel PaRAM set. EDMA3_DRV_getPaRAM(EdmaObj->hEdma, EdmaObj->iChannel, &channelParam); EDMA3_DRV_getPaRAM(EdmaObj->hEdma, EdmaObj->iReloadPing, &pingParam); EDMA3_DRV_getPaRAM(EdmaObj->hEdma, EdmaObj->iReloadPong, &pongParam); } // ============================ EDMA START ======================================= // // This function will set the Event Enable Register (EER) bit corresponding to the // channel we are using. To do this, we use EDMA3_DRV_TRIG_MODE_EVENT in the // _enableTransfer call below. After the first "A-size" transfer is complete, an // interrupt to the CPU is generated (intermediate interrupts turned on), then we wait // for another sync event (from Timer 0) and this goes on until all 16 transfers are // complete. Then, the semaphore is posted in edma_isr that signals edmaTsk that we // are finished. // // This function could be improved by returning the result. // =================================================================================== void edma_start(edma_object_t EdmaObj) { EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; edma3Result = EDMA3_DRV_enableTransfer(EdmaObj.hEdma, EdmaObj.iChannel, EDMA3_DRV_TRIG_MODE_EVENT); } // ============================ EDMA DELETE CHANNEL ============================= // // Delete (free) the current channel from the resource pool // =================================================================================== void edma_deleteChan(edma_object_t EdmaObj) { EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; edma3Result = EDMA3_DRV_freeChannel(EdmaObj.hEdma, EdmaObj.iChannel); } // ============================ EDMA WAIT ======================================= // // Check to see if the EDMA3 interrupt pending register (IPR) is set to one indicating // that the transfer has completed. This is a blocking function - it will continue to // poll the IPR bit and won't return until it becomes a 1. // // This function could be improved by returning the result. Also, adding a timeout // feature would be an improvement. // =================================================================================== void edma_wait(edma_object_t EdmaObj) { EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; edma3Result = EDMA3_DRV_waitAndClearTcc(EdmaObj.hEdma, EdmaObj.iTcc); } // ============================ EDMA CHECK ====================================== // // Check to see if the EDMA3 interrupt pending register (IPR) is set to one indicating // that the transfer has completed. This is a one-time check - not a blocking // function. The calling code can check the status and respond accordingly. // // tccStatus = TRUE or FALSE // =================================================================================== unsigned short edma_check(edma_object_t EdmaObj) { unsigned short tccStatus; EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; edma3Result = EDMA3_DRV_checkAndClearTcc(EdmaObj.hEdma, EdmaObj.iTcc, &tccStatus); return(tccStatus); } // ============================ EDMA RELEASE ====================================== // // EDMA3_DRV_close is used to close an already opened EDMA3 Driver instance. // // EDMA3_DRV_delete deletes the driver instance and driver object. // ===================================================================================== void edma_release(edma_object_t EdmaObj) { EDMA3_DRV_Result edma3Result = EDMA3_DRV_SOK; edma3Result = EDMA3_DRV_close(EdmaObj.hEdma, NULL); edma3Result = EDMA3_DRV_delete(edma3InstanceId, NULL); } // =============================== EDMA ISRS ====================================== // // When RCV transfer is complete, the interrupt dispatcher calls the "callback" function // for RCV (tccCbRcv) which is set to edma_rcv_isr. The ISR simply posts the semaphore // to procBuffTsk (in tasks.c) to copy Rcv to Xmt. Same method applies for Xmt. // // EDMA3_DRV_delete deletes the driver instance and driver object. // ===================================================================================== void edma_rcv_isr(void) { SEM_post(&rcvBuffReady); } void edma_xmt_isr(void) { SEM_post(&xmtBuffReady); } /* ========================== END OF FILE =========================== */
// ============================= INCLUDES ========================================= #include <stdint.h> // used for int16_t definitions #include "edma_codec_config.h" // includes definitions for BUFFSIZE and externs for Src/Dst #include "edma.h" // includes prototypes for all edma functions #include "main.h" //#include "mcbsp_aic23.h" // contains definitions used in mcbsp_aic23.c #include <stdint.h> // used for definitions like uint32_t, ... //#include <string.h> // used for memset/memcpy commands #include <std.h> #include <c6x.h> // interrupt functions/defines #include <c64.h> //#include <src\edma3_rl_cc.h> // needed for CCRegsPtr overlay - for debug #include <edma3_rl_cc.h> // needed for CCRegsPtr overlay - for debug #include "codec.h" #pragma DATA_SECTION(gBufferXmt,".TX_FIFOS") int16_t gBufferXmt[2][BUFFSIZE_TX]; // Transmit PING & PONG buffers //#pragma DATA_SECTION(gBufferRcv,".TX_FIFOS") int16_t gBufferRcv[2][BUFFSIZE]; // Receive PING & PONG buffers extern EDMA3_CCRL_RegsOvly CCRegsPtr; int16_t *pDRR;// = (void *) 0x01D00800; int16_t *pDXR;// = (void *) 0x01D00804; void init_buffers(void); void edma_codec_init_config() { // Initialize our Edma Rcv/Xmt objects - passed to edma_config() and edma_createChan() in edma.c edma_object_t EdmaObjRcv = {NULL, // hEdma: handle to be returned by our edma_config function EDMA_HW_EVENT_REVT1, // iRcv: need to use Event 15 - because it is tied to McBSP1 Rcv EDMA3_DRV_TCC_ANY, // iRcvTcc: use ANY TCC EDMA3_DRV_LINK_CHANNEL, // RcvPing link PSET EDMA3_DRV_LINK_CHANNEL}; // RcvPong link PSET edma_object_t EdmaObjXmt = {NULL, // hEdma: handle to be returned by our edma_config function EDMA_HW_EVENT_XEVT1, // iChannel: need to use Event 14 - because it is tied to McBSP1 Xmt EDMA3_DRV_TCC_ANY, // iTcc: use ANY TCC EDMA3_DRV_LINK_CHANNEL, // XmtPing link PSET EDMA3_DRV_LINK_CHANNEL}; // XmtPong link PSET *pDRR = MCBSP1_DRR_32BIT; //0x01D00800; *pDXR = MCBSP1_DXR_32BIT; //0x01D00804; EVM6424_init(); // init EVM6437 HW (void)initCodec(); // init McBSP1; s/u AIC via I2C init_buffers(); // Create and open edma3 driver and instance edma_config(&EdmaObjRcv); EdmaObjXmt.hEdma = EdmaObjRcv.hEdma; edma_createChan(&EdmaObjRcv, pDRR, gBufferRcv[0]); edma_createChan(&EdmaObjXmt, gBufferXmt[0], pDXR); edma_start(EdmaObjRcv); edma_start(EdmaObjXmt); // enable EINT5 - please refer to HWI_INT5 in .tcf file for proper settings C64_enableIER(C64_EINT5); // MCBSP1_SPCR = 0x00010001; // start McBSP } void do_nothing(void) { while(1); } void init_buffers(void) { // clear the destination buffers memset(gBufferRcv, 0, sizeof(gBufferRcv)); memset(gBufferXmt, 0, sizeof(gBufferXmt)); } // ================================ END OF FILE ====================================