This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LC4357: MIBSPI RX DMA triggers on buffers other than the last in a transfer group don't work reliably

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

I have observed that MIBSPI RX DMA triggers on any but the last buffer in a transfer group don't fire if there is too long between writing to that buffer and the next one, when using loopback and "suspend single-transfer" or "suspend single-transfer overwrite-protect" buffer modes. I do not understand what "too long" means exactly, but it's longer than waiting for the INTFLGSUS bit to be set and does depend somewhat on the configured baud rate. What constraints must I follow to ensure the DMA channels are reliably triggered?

Note that I am seeing similar symptoms where a DMA channel isn't triggered as many times as it should be with real code talking to another MCU out of loopback mode and using non-suspend buffer modes, which I think might be the same problem, but that one is much harder to reproduce due to timing and other complexities so I think it makes sense to try and resolve the easily reproducible case with loopback first.

  • 2262.MIBSPI-DMA weirdness repro TI toolchain.zip

    Attached is a CCS project for a TMS570LC4357 HDK which demonstrates the problem. Everything but HL_sys_main.c is unmodified HALCOGEN output. It prints output on SCI1 (the one hooked up over USB on an HDK) at 115,200 baud. In HL_sys_main.c there is a #if tree to configure which method is used to write to the peripheral. I'm pretty sure all three should yield the same result of both MIBSPI DMA channel firing (and then disabling themselves because they are in ONESHOT mode), and using mibspiSetData or just writing to the buffers sequentially does give that result. However, when inserting a printf between writing to the two buffers (as a relatively long delay), the first DMA channel does not fire. I have verified in more complex tests that an attached DMA channel actually fails to fire, but in this simplified example I did not configure any actual DMA channels to keep it simpler.

    Apologies for two comments. I couldn't figure out how to attach the file in my original post...

  • Update: while debugging a workaround, I ended up modifying the MCU sending data to the Hercules to insert (relatively long) pauses between each frame. This does indeed reliably reproduce this behavior in non-loopback mode, and on the last buffer in a transfer group too.

  • Hello Brian,

    What does "the first DMA channel does not fire" mean in your 2nd post? I just took a look at your sample code, you don't enable and use DMA to transfer data to/from the MibSPI RAM.
  • As stated in my original post, I avoided actually configuring the DMA in my example to simplify it. I am talking exclusively about the DMA channel in the MIBSPI peripheral instead, which is what doesn't fire. The TRM describes "DMAxCTRL" registers as "DMA Channel Control Register", so that is the best description I can think of; please let me know if there's a less confusing term to use instead.

    Specifically, the COUNTx field in the DMA0CTRL register fails to decrement, which would also cause the RXDMAENAx field to change to 0 because the ONESHOT field is set to 1. That is what occurs without long delays between writing the two frames, but fails to occur when a delay is inserted between them.

  • Any updates on this? It's been 24 hours since I responded, and well over a week now with no substantive response from TI. This seems like a pretty crippling problem with the DMA functionality of the MIBSPI peripheral, and I would very much like to know if there are any workarounds.

  • Hello Brian,

    The MibSPI offers up to eight DMA channels (for TX and RX). All of the DMA channels are individually programmable and can be hooked up to any buffer in the multi-buffer RAM. The MibSPIP provides up to 16 DMA request lines, DMA requests from any channel can be programmed to be routed through any of these 16 lines. A DMA transfer can be triggered by both TX and RX events.

    Only one DMA read channel and one DMA write channel can be assigned to 1 transfer group. You can not assign DMA channel0 to TG0 word0, and DMA channel1 to TG0 word1, and so on.

  • Hi,

    Thanks for the summary of how the MIBSPI-DMA channels work. It agrees with my understanding from the TRM.

    Your theory that the problem is using two MIBSPI-DMA channels in the same transfer group does not appear to match reality. I did not explicitly state it originally, but I had previously observed this behavior with only a single MIBSPI-DMA channel configured. My example code only uses two to demonstrate that they are configured correctly and will sometimes trigger. My posted example code with the second MIBSPI-DMA channel (mibspiREG1->DMACTRL[1]) commented out displays the exact same behavior with the first channel, where it doesn't fire when there's a delay between writing data to the first and second buffers in the transfer group. Here is a modified version with that commented out is attached to be 100% clear on what I'm talking about: 8117.MIBSPI-DMA weirdness repro TI toolchain single DMA.zip

    Also, the TRM and datasheet make no reference to such a restriction that I can find; please point out where that is if I missed it. Additionally, TI's spna231 application note (High Speed Serial Bus Using the MibSPIP Module on Hercules™-Based Microcontrollers, by Christian Herget) even uses an example configuration with two receive MIBSPI-DMA channels in a single transfer group.

    Please look at this problem again, because your explanation does not seem correct.

    Brian Silverman

  • Hello Brian,

    Sorry for my misleading message. Sure, you can assign different channels to different buffers in the same transfer group. But there is only one trigger event for one transfer group. For example, the TG0 has 4 buffers, the DMA channel 0 is assigned to TG0 buffer0, the DMA channel 1 is assigned to TG0 buffer1, the DMA channel 2 is assigned to TG0 buffer2, and the DMA channel 3 is assigned to TG0 buffer3, whenever the defined trigger event occurs, all the buffers will be transferred.

    I modified your project to add the code reading the data from the TG0 buffer0/1/2/3 through DMA. It works well. Only one trigger is for the whole group (TG0).

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/312/4645.MIBSPI_2D00_DMA-weirdness-repro-TI-toolchain.7z

  • Hi Brian,

    The followings show the test results of the modifiedprojects:

    1. at breakpoint 1 (line 190):

    The count number in DMAxCtrl are all 0x1. 

    TX data for 4 DMA channels are 0x5A01, 0x5A02, 0x5A03, and 0x5A04. RXDATA00/01/02/04 are the data the DMA transferred from MibSPI RAM to MCU SRAM

    MibSPI RAM: TX data, and RX data

    2. AT breakpoint 2 (Line 202)

    The count is decreased to 0x0

    The received data is same as the TX data:

    TX data in MibSPI RAM:

    MibSPI RAM: RX data

  • I agree that it works fine if you modify it so that the receive buffers are transferred into without delays between the transfers. That is the effect of moving the mibspiTransfer call like you did. However, as stated in my original post and followups, the problematic behavior I'm observing is only when there are delays between transferring into receive buffers, whether that's because of delays between writing to the transmit buffers in loopback mode, or delays inserted by the external master in non-loopback mode. If I uncomment the mibspiTransfer call above transferring into the buffers in your latest test code, I observe the problematic behavior again:

    > mdw 0xFFF7F4d8
    0xfff7f4d8: 80108001
    > mdw 0xFFF7F4dc
    0xfff7f4dc: 81008001
    > mdw 0xFFF7F4e0
    0xfff7f4e0: 82a08001
    > mdw 0xFFF7F4e4
    0xfff7f4e4: 83300000

    For reference, here's what it looks like running the code you attached unmodified (with the mibspiTransfer call after moving the data). I haven't figured out how to get CCS cloud to talk to my HDK, so I'm just using openocd instead:

    > mdw 0xFFF7F4d8
    0xfff7f4d8: 80100000
    > mdw 0xFFF7F4dc
    0xfff7f4dc: 81000000
    > mdw 0xFFF7F4e0
    0xfff7f4e0: 82a00000
    > mdw 0xFFF7F4e4
    0xfff7f4e4: 83300000

  • Hello Brian,

    If you want to use delay between different DMA transfer channels, I recommend you to use different transfer groups. Each DAM channel hooks to one transfer group. You can have up to 8 transfer group, and each group can has 1~127 buffers. Each transfer group can use different trigger source and trigger event.

    This is what TRM says:

    • Configure one of the eight BUFMODE available for each buffer.
    • Fill the data to be transmitted in TXDATA field in TXRAM buffers.
    • Configure TGENA bit to enable the required Transfer groups. 
    • At the occurrence of the correct trigger event, the Transfer group will be triggered and data gets transmitted and received one after the other with out any CPU intervention.
    • You can poll Transfer group interrupt flag or wait for a transfer-completed interrupt to read and write new data to the buffers.

  • I'm not trying to add delays. I'm trying to receive data from an external master using the Hercules as a slave. However, I need to know what the requirements on the timing from the external master are to have it work reliably, so I can evaluate if my design will work with this external master or if I need to redesign to work around this (severe) limitation of the Hercules. I don't see anything in the TRM or datasheet mentioning a "maximum delay between frames" or anything similar, so I am at a loss as to why there appears to be such a requirement on the acceptable SPI masters the Hercules will work with.

    This all started when I observed the MIBSPI-DMA triggers not behaving correctly in my full application with a separate external master and various other complications. The example we've been discussing is just that: an example. It is deliberately (highly) simplified such that it only uses a single Hercules to reproduce the problem, and does that in loopback mode. Again: I'm trying to understand how to reliably receive data via the MIBSPI peripheral with DMA with the Hercules acting as a slave, so suggestions to how to make the Hercules work differently as a master are irrelevant.

    Also, I only have a single CS line between the external master and the Hercules. The TRM makes it pretty clear in "28.2.6.7 MibSPI Slave in Multi-buffer Configuration" that this means I can only use a single transfer group. Given this, I don't see how your latest suggestion applies at all.

  • Hi Brian,

    I run your project, and reproduced the same problem. The 2nd received data didn't trigger the DMA transfer.

    This is the reason: One TX side, 2 buffers are used in the TG, the data in those 2 buffers are looped back to 2 buffers on RX RAM. But only 1 buffer is transferred by DMA. The 2nd buffer won't trigger the DMA transfer.

    I will modify your code to use SPI1 and SPI3 rather loopback.

    SPI1: Master, couple channels with delay, 1 TG
    SPI3: slave, 1 channel, and 1 TG

    Come back to you tommorrow
  • Hello Brain,

    For adding delay between buffers, please use WDELAY which is defined in FMT0 (Data Format 0).

       mibspiREG1->FMT0 = (uint32)((uint32)10U << 24U)  /* wdelay */

    This feature is enabled for MibSPI is in MibSPI RAM setting for each buffer :

                  mibspiRAM1->tx[i].control = (uint16)((uint16)4U << 13U)  /* buffer mode */

                                             | (uint16)((uint16)1U << 12U)  /* chip select hold */

                                             | (uint16)((uint16)0U << 10U)  /* enable WDELAY */

                                             | (uint16)((uint16)0U << 11U)  /* lock transmission */

                                             | (uint16)((uint16)0U << 8U)  /* data format */

                                             | ((uint16)(~((uint16)0xFFU ^ (uint16)CS_0)) & (uint16)0x00FFU);  /* chip select */

    The delay can be up to 257 VCLK cycles. For example, the VCLK is 100MHz, the maximum delay can be 2.57us.

  • Hello Brian,

    The delay between the transmission of two buffers doesn't impact the data receiving and the DMA transfer in slave side. The trigger method in your code is not correct. One transfer group has only one trigger event and one trigger source. The trigger should be issued when all the buffers in the transfer group are ready. 

    If you want to test the impact of the delay, please use WDELAY in FMTx register. Attached is an example code.

    1. MibSPI1: master, 1 TG with 8 buffers, data are written to TXRAM directly. The transmission delay between two buffers is 3.43uS (WDELAY=0xFF).

    2. MiSPI3: slave, 1 TG with only 1 buffer, DMA is used to transfer data from RXRAM to SRAM (data array)

    The data is transferred and received correctly.

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/312/4186.TMS570LC4357_5F00_MibSPI1_2600_3_5F00_DMA.7z 

  • Hello Brian,

    Could you please check my example code to see if it meets your requirements? I added comments for MibSPI DMA settings, Transfer Group setting, MiSPI RAM configuration. Any questions, please let us know. The following is the code of main() function of my sample project:

    /* Include Files */

    #include "HL_sys_common.h"

    /* USER CODE BEGIN (1) */

    #include "HL_mibspi.h"

    #include "HL_sys_dma.h"

    #include "HL_sys_core.h"

    #include "HL_sci.h"

    #include "HL_reg_esm.h"

    #include <stdio.h>

    #include <string.h>

    #define E_COUNT      1   /*Element count*/

    #define F_COUNT      8   /*Frame count*/

    #define D_SIZE      E_COUNT * F_COUNT

    #define TG0         1

    #define TG1         0

    /* USER CODE END */

    /** @fn void main(void)

    *   @brief Application main function

    *   @note This function is empty by default.

    *

    *   This function is called after startup.

    *   The user can use this function to implement the application.

    */

    /* USER CODE BEGIN (2) */

    void loadDataPattern(uint32 psize, uint16* pptr, uint16 pattern);

    void dmaConfigCtrlRxPacket(uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt);

    void dmaConfigCtrlTxPacket(uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt);

    /* TG start address */

    uint16 tgPSTART[8];

    g_dmaCTRL g_dmaCTRLPKT_RX, g_dmaCTRLPKT_TX;

    #pragma SET_DATA_SECTION(".sharedRAM")

    uint16 TXDATA[D_SIZE];         /* transmit buffer in sys ram, MibSPI1 TG0 */

    uint16 RXDATA[D_SIZE]= {0};    /* receive  buffer in sys ram, MibSPI1 TG0 */

    #pragma SET_DATA_SECTION()

    uint16 tx_data1[8] = {0x5A11,0x5A22,0x5A33,0x5A44,0x5A55,0x5A66,0x5A77,0x5A88};

    /* USER CODE END */

    int main(void)

    {

    /* USER CODE BEGIN (3) */

       uint16 i;

       esmREG->SR1[0] = 0xFFFFFFFF;

       esmREG->SR1[1] = 0xFFFFFFFF;

       esmREG->SR1[2] = 0xFFFFFFFF;

       esmREG->EKR = 0x0000000A;

       esmREG->EKR = 0x00000000;

        sciInit();

        printf("hello\n");

        /*Enable RQ interrupt*/

       _enable_IRQ_interrupt_();

       /* initializing MibSPI1 and MibSPI3 - enabling tg 0 , length 127 (halcogen file)*/

       mibspiInit();

       /* Delay in between transmissions or between 2 buffer frames */

       /* The delay to be applied is equal to:  (WDELAY + 2) × PVCLK, where PVCLK is the Period of VCLK */

       /* In this example, VCLK=75MHz, PVCLK=13.33ns, the delay between 2 buffer frame is: 257*13.33=3.43us*/

       mibspiREG1->FMT0 &= (uint32)(0x00FFFFFF);  /* clear the WDELAY bits: bit 31~24 */

       mibspiREG1->FMT0 |= (uint32)(0xFF << 24);  /* add delay: 0xFF, maximum */

       /* MibSPI1: master

        * TG0: 8 buffers,

        * Oneshot transfer is set: A transfer from TG0 will be performed only once after a valid trigger event

        * Trigger event: always

        * Trigger source: disabled

        * By setting the TRIGSRC to 0, the TRIGEVT to 7h (ALWAYS), and the ONESHOTx bit to 1, software can trigger

        * this TG. Upon setting the TGENA bit, the TG is immediately triggered.

        */

       mibspiREG1->TGCTRL[0U] = (uint32)((uint32)1U << 30U)  /* oneshot */

                              | (uint32)((uint32)0U << 29U)  /* pcurrent reset */

                              | (uint32)((uint32)TRG_ALWAYS<< 20U)  /* trigger event */

                              | (uint32)((uint32)TRG_DISABLED << 16U)  /* trigger source */

                              | (uint32)((uint32)0U << 8U);  /* start buffer */

       mibspiREG1->TGCTRL[1U] = (uint32)((uint32)1U << 30U)  /* oneshot */

                              | (uint32)((uint32)0U << 29U)  /* pcurrent reset */

                              | (uint32)((uint32)TRG_ALWAYS << 20U)  /* trigger event */

                              | (uint32)((uint32)TRG_DISABLED << 16U)  /* trigger source */

                              | (uint32)((uint32)8U << 8U);  /* start buffer */

       /* Configure the TX RAM of MibSPI1 TG0:

        * Bufmode: suspend single-transfer mode. Suspend-to-wait until the corresponding TXFULL flag is set (the sequencer stops

        *          at the current buffer until new transmit data is written in the TXDATA field).

        * Chip Select Hold: off, the chip select signal is deactivated at the end of a transfer

        * WDELAY is enabled, the delay is defined in FMT0

        * Lock transmission: disabled, any higher-priority TG can begin at the end of the current transaction

        * Data fornat: FMT0

        * Chip Select: CS0

        * */

       for (i=0; i<8; i++)

       {

           mibspiRAM1->tx[i].control = (uint16)((uint16)5U << 13U)  /* buffer mode */

                                     | (uint16)((uint16)0U << 12U)  /* chip select hold */

                                     | (uint16)((uint16)1U << 10U)  /* enable WDELAY */

                                     | (uint16)((uint16)0U << 11U)  /* lock transmission */

                                     | (uint16)((uint16)0U << 8U)  /* data format */

                                     | ((uint16)(~((uint16)0xFFU ^ (uint16)CS_0)) & (uint16)0x00FFU);  /* chip select */

       }

       /* MibSPI3: Slave, 1 TG

        * TG0: 1 buffer only

        * Oneshot transfer is reset: TGx initiates a transfer every time a trigger event occurs and TGENA is set.

        * In slave mode, the fields like trigger source and trigger event are not taken into account by the sequencer.

        * Only the SPICS pins can trigger a Transfer Group.

        * */

       mibspiREG3->TGCTRL[0U] = (uint32)((uint32)0U << 30U)  /* oneshot */

                              | (uint32)((uint32)0U << 29U)  /* pcurrent reset */

                              | (uint32)((uint32)TRG_ALWAYS << 20U)  /* trigger event */

                              | (uint32)((uint32)TRG_DISABLED << 16U)  /* trigger source */

                              | (uint32)((uint32)0U << 8U);  /* start buffer */

       mibspiREG3->TGCTRL[1U] = (uint32)((uint32)0U << 30U)  /* oneshot */

                              | (uint32)((uint32)0U << 29U)  /* pcurrent reset */

                              | (uint32)((uint32)TRG_ALWAYS << 20U)  /* trigger event */

                              | (uint32)((uint32)TRG_DISABLED << 16)  /* trigger source */

                              | (uint32)((uint32)1U << 8U);  /* start buffer */

       /* Configure the TX RAM of MibSPI1 TG0:

        * Bufmode: suspend overwrite-protect mode. Suspend-to-wait until the corresponding RXEMPTY flag is set

        *          (the sequencer stops at the current buffer until the previously-received data is read by the host.)

        * Chip Select Hold: 0. If the CSHOLD bit in a buffer is cleared to 0 in a slave MibSPI, even after the shift operation is done,

        * the MibSPI waits until the SPICS pin is deasserted to copy the received data to the RXRAM.

        * If the CSHOLD bit is maintained as 0 across all the buffers, then the slave in multi-buffer mode requires its

        * SPICS pins to be deasserted between any two buffer transfers; otherwise, the Slave SPI will be unable to

        * respond to the next data transfer.

        * Data fornat: FMT0

        * Chip Select: CS0

        * */

       for(i=0; i<1; i++){

            mibspiRAM3->tx[i].control = (uint16)((uint16)6U << 13U)  /* buffer mode */

                                      | (uint16)((uint16)0U << 12U) /* chip select hold */

                                      | (uint16)((uint16)0U << 10U)  /* enable WDELAY */

                                      | (uint16)((uint16)0U << 8U)  /* data format */

                                      | ((uint16)(~((uint16)0xFFU ^ (uint16)CS_0)) & (uint16)0x00FFU);  /* chip select */

      }

    #if 0

       /* TG start address. PSTARTx stores the start address of the corresponding TG. The corresponding */

       /* end address is inherently defined by the subsequent TG start address minus 1 (PENDx[TGx] =    */

       /* PSTARTx[TGx+1]-1). PSTARTx is copied into PCURRENTx when:*/

       for(i=0; i<8; i++){

          tgPSTART[i] = (mibspiREG1->TGCTRL[i] >> 8) & 0xFF;

       }

       /*MibSPI1 TG0, DMA config*/

       /* - creating a data chunk in system ram to start with ... */

       /* TXDATA_TG10 ->MibSPI1 TG0 */

       loadDataPattern(D_SIZE, &TXDATA[0], 0x5A00);

       dmaConfigCtrlTxPacket((uint32)TXDATA, (uint32)&(mibspiRAM1->tx[tgPSTART[0]].data), E_COUNT, F_COUNT);

       //using DAM_CH0 for RX, DMA_CH1 for TX

       /* - setting dma control packets */

       dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_TX);  //tx

       dmaSetChEnable(DMA_CH1, DMA_HW);

       dmaReqAssign(DMA_CH1, DMA_REQ1); //DMA request line 1, TX

       // Set up the MIBSPI DMA channel triggers.

       uint32_t dmactrl_base1 = (1u << 31) /* ONESHOT */

                              | (1u << 14) /* TXDMAEN */

                              | (7u << 8) /* ICOUNT */;

       mibspiREG1->DMACTRL[0] = dmactrl_base1

                              | (7u << 24) /* BUFID */

                              | (0u << 16) /* TXDMA_MAP */;

    #endif

       /* MibSPI3, Slave, TG0, DMA*/

       /* DMA source address: MibSPI RX RAM buffer 0 */

       /* DMA destination address: data array: RXDATA[] */

       /* DMA Channel 8, request line: 5*/

       dmaConfigCtrlRxPacket((uint32)&(mibspiRAM3->rx[0].data), (uint32)RXDATA, E_COUNT, F_COUNT);

       /* - setting dma control packets */

       dmaSetCtrlPacket(DMA_CH8,g_dmaCTRLPKT_RX);  //rx

       dmaSetChEnable(DMA_CH8, DMA_HW);

       dmaReqAssign(DMA_CH8, DMA_REQ5);

       /* Select the DMAxCOUNT counters. Writes to the DMAxCTRL register will not modify the ICOUNT value.

        * The ICOUNT value must be written to in the DMAxCOUNT register before the RXDMAENA or TXDMAENA bits are set in the

        * DMAxCTRL register. The DMAxCOUNT register should be used for reading COUNT or ICOUNT.

        * */

       mibspiREG3->DMACNTLEN = 0x1;

       mibspiREG3->DMACOUNT[0] = (F_COUNT*E_COUNT - 1) << 16;

       /* Set up the MIBSPI DMA channel triggers.

        * Oneshot is set. allows a block transfer of defined length (ICOUNTx+1)

        * BUFID is 0 (E_COUNT=1)

        * */

       uint32_t dmactrl_base3 = (1u << 31) /* ONESHOT */

                              | (1u << 15) /* RXDMAEN */

                              | (7u << 8) /* ICOUNT */;

       mibspiREG3->DMACTRL[0] = dmactrl_base3

                              | ((E_COUNT - 1) << 24) /* BUFID */

                              | (3u << 20) /* RXDMA_MAP */;

       /* Enable the DMA */

       dmaEnable();

       /* Enable MibSPI3 transfer group 0*/

       mibspiTransfer(mibspiREG3, 0);

       /* Write data directly to TX RAM buffers: 8 buffers are configured

        * The transmission delay between 2 buffers is defined in FMT0. It is 3.43us

        * */

       mibspiRAM1->tx[0].data = tx_data1[0];

       mibspiRAM1->tx[1].data = tx_data1[1];

       mibspiRAM1->tx[2].data = tx_data1[2];

       mibspiRAM1->tx[3].data = tx_data1[3];

       mibspiRAM1->tx[4].data = tx_data1[4];

       mibspiRAM1->tx[5].data = tx_data1[5];

       mibspiRAM1->tx[6].data = tx_data1[6];

       mibspiRAM1->tx[7].data = tx_data1[7];

       /* - start the mibspi transfer tg 0

        * Each transfer group has only 1 trigger event and trigger source. The trigger is issued when all the buffers in this

        * transfer group is ready to transfer

        *

        * This SW trigger is a pulse

        * */

       mibspiTransfer(mibspiREG1, 0);

    while(1);

     /* USER CODE END */

       return 0;

    }

    /* USER CODE BEGIN (4) */

    /** configuring mibspi dma with

    *

    *       channel   > mibspi dma channel number

    *       txchannel > transmit channel dedicated for mibspi

    *       rxchannel > receive  channel dedicated for mibspi

    */

    void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel)

    {

       //uint32 bufid  = (channel + 1) * E_COUNT - 1;

       uint32 bufid  = tgPSTART[channel] + E_COUNT - 1;

       /* setting transmit and receive channels */

       mibspi->DMACTRL[channel] |= (rxchannel << 20) | (txchannel << 16);

       if (F_COUNT > 1) {

            mibspi->TGCTRL[channel] &= 0xBFFFFFFF; // Disable ONESHOT

       } else {

            mibspi->TGCTRL[channel] |= 0x40000000; // Enable ONESHOT

       }

       /* enabling transmit and receive dma */

       mibspi->DMACTRL[channel] |=  0x8000C000;

       /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */

       mibspi->DMACTRL[channel] |=  (bufid<<24);

       /* Enable Large count transfer */

       mibspi->DMACNTLEN = 0x1;

       mibspi->DMACOUNT[channel] = (F_COUNT - 1) << 16;

    }

    void loadDataPattern(uint32 psize, uint16* pptr, uint16 pattern)

    {

       int i;

       for(i=0;i<psize;i++)

       {

           *(pptr++) = pattern + i;

       }

    }

    void dmaConfigCtrlTxPacket(uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt)

    {

         g_dmaCTRLPKT_TX.SADD       = sadd;               /* source address             */

         g_dmaCTRLPKT_TX.DADD       = dadd;               /* destination  address       */

         g_dmaCTRLPKT_TX.CHCTRL     = 0;                  /* channel control            */

         g_dmaCTRLPKT_TX.FRCNT      = FrameCnt ;          /* frame count                */

         g_dmaCTRLPKT_TX.ELCNT      = ElmntCnt;           /* element count              */

         g_dmaCTRLPKT_TX.ELDOFFSET  = 4;                  /* element destination offset */

         g_dmaCTRLPKT_TX.ELSOFFSET  = 0;                  /* element source offset */

         g_dmaCTRLPKT_TX.FRDOFFSET  = 0;                  /* frame destination offset   */

         g_dmaCTRLPKT_TX.FRSOFFSET  = 0;                  /* frame destination offset   */

         g_dmaCTRLPKT_TX.PORTASGN   = PORTA_READ_PORTB_WRITE;                 /* port b                     */

         g_dmaCTRLPKT_TX.RDSIZE     = ACCESS_16_BIT;      /* read size                  */

         g_dmaCTRLPKT_TX.WRSIZE     = ACCESS_16_BIT;      /* write size                 */

         g_dmaCTRLPKT_TX.TTYPE      = FRAME_TRANSFER ;    /* transfer type              */

         g_dmaCTRLPKT_TX.ADDMODERD  = ADDR_INC1;          /* address mode read          */

         g_dmaCTRLPKT_TX.ADDMODEWR  = ADDR_OFFSET;        /* address mode write         */

         g_dmaCTRLPKT_TX.AUTOINIT   = AUTOINIT_OFF;       /* autoinit                   */

         //return g_dmaCTRLPKT_TX;

    }

    void dmaConfigCtrlRxPacket(uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt)

    {

         g_dmaCTRLPKT_RX.SADD       = sadd;              /* source address             */

         g_dmaCTRLPKT_RX.DADD       = dadd;           /* destination  address       */

         g_dmaCTRLPKT_RX.CHCTRL     = 0;                 /* channel control            */

         g_dmaCTRLPKT_RX.FRCNT      = FrameCnt;                 /* frame count                */

         g_dmaCTRLPKT_RX.ELCNT      = ElmntCnt;             /* element count              */

         g_dmaCTRLPKT_RX.ELDOFFSET  = 0;                 /* element destination offset */

         g_dmaCTRLPKT_RX.ELSOFFSET  = 4;                 /* element destination offset */

         g_dmaCTRLPKT_RX.FRDOFFSET  = 0;                  /* frame destination offset   */

         g_dmaCTRLPKT_RX.FRSOFFSET  = 0;                 /* frame destination offset   */

         g_dmaCTRLPKT_RX.PORTASGN   = PORTB_READ_PORTA_WRITE;   /* port b                     */

         g_dmaCTRLPKT_RX.RDSIZE     = ACCESS_16_BIT;      /* read size                  */

         g_dmaCTRLPKT_RX.WRSIZE     = ACCESS_16_BIT;      /* write size                 */

         g_dmaCTRLPKT_RX.TTYPE      = FRAME_TRANSFER ;   /* transfer type              */

         g_dmaCTRLPKT_RX.ADDMODERD  = ADDR_OFFSET;         /* address mode read          */

         g_dmaCTRLPKT_RX.ADDMODEWR  = ADDR_INC1;       /* address mode write         */

         g_dmaCTRLPKT_RX.AUTOINIT   = AUTOINIT_ON;       /* autoinit                   */

         //return g_dmaCTRLPKT_RX;

    }