Circular DMA Buffer

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Circular DMA Buffer

Jump to solution
3,368 Views
kenrenjen
Contributor III

Hi

I am using flextimer and configured them to trigger DMA when it reach a rising edge in the channel interrupt. I defined a specific size of the DMA buffer, which gives me some problems, as I don't know how many inputs i get.

First question: Is it possible somehow to make a circular DMA buffer? and how?

Second question: If I want to clear the DMA and start all over before the buffer is full, how do I do this in a correct way? Right now I have to initialize the controller again.

I posted my code for initializing the DMA, I hope someone can help me out.

I have a DMA buffer which has 2048 elements of uint16.

I am working on a K60 MCU using uTasker.

Thanks in advance.

// Configure DMA multiplexer and DMA controller

void dma_init(void)

{

  POWER_UP(6, SIM_SCGC6_DMAMUX0);

  POWER_UP(7, SIM_SCGC7_DMA);

  DMAMUX0_CHCFG0 = (DMAMUX_CHCFG_SOURCE_FTM0_CH0 | DMAMUX_CHCFG_ENBL);

  /* No link channel to channel, number of transactions */

  DMA_TCD0_CITER_ELINKNO = buffer_size; // Current Minor Loop Link, Major Loop Count

  DMA_TCD0_BITER_ELINKNO = buffer_size; // Beginning Minor Loop Link, Major Loop Count

  /* transfer, making only a single minor loop necessary to complete a major loop */

  DMA_TCD0_SADDR = (uint32)(&FTM0_C0V); // Set the Source Address

  DMA_TCD0_SOFF = 0; // Source offset disabled

  DMA_TCD0_SLAST = 0; // Last Source Address Adjustment - No adjust needed

  DMA_TCD0_DADDR = (uint32)dma_buf; // Set the Destination Address

  DMA_TCD0_DOFF = sizeof(uint16); // Destination offset 2 bytes (Increments the address after transaction)

  DMA_TCD0_DLASTSGA = -(sizeof(uint16)*(buffer_size)); // Last Destination Address Adjustment (2 byte * array size)

  DMA_TCD0_NBYTES_MLNO = sizeof(uint16); // Transfer 2 bytes per transaction (16 bit)

  /* Source and Destination Modulo off, source and destination size 1 = 16 bits */

  DMA_TCD0_ATTR =  DMA_TCD_ATTR_SSIZE_16_BIT | DMA_TCD_ATTR_DSIZE_16_BIT;

  DMA_ERQ |= DMA_ERQ_ERQ0; // Enable DMA request on channel 0

}

Labels (1)
0 Kudos
1 Solution
1,556 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

1. The circular DMA buffer is eanabled via set TCD Transfer Attributes (DMA_TCDn_ATTR) register [SMOD] & [DMOD] bits.

Please check attached example code, which is using circular DMA buffer to do eDMA performance test.

2. You can disable the DMA trigger source(disable FTM DMA trigger) and move data from the buffer. After that, you can enable the DMA trigger again.

Wish it helps.

View solution in original post

0 Kudos
2 Replies
1,557 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

1. The circular DMA buffer is eanabled via set TCD Transfer Attributes (DMA_TCDn_ATTR) register [SMOD] & [DMOD] bits.

Please check attached example code, which is using circular DMA buffer to do eDMA performance test.

2. You can disable the DMA trigger source(disable FTM DMA trigger) and move data from the buffer. After that, you can enable the DMA trigger again.

Wish it helps.

0 Kudos
1,557 Views
jinxin_cn
Contributor I

Hi Ma Hui,

I referred your demo code. And initial the lpuart as below. But I cannot receive anything in g_ui8RxBuffer[], am I lost something? By the way, because our protocol is based on 16-bit big-endian mode, could I configure kEDMATransferSize_1Bytes to kEDMATransferSize_2Bytes and make transform from big-endian to little-endian in 16-bit type?

Thanks in advance!

void InitUartDrv(void)

{

    uint32_t dmaBaseAddr;

    uint32_t dmaChannel;

    uint32_t baseAddr = g_lpuartBaseAddr[0];

  /*

  * initial lpuart driver for commlink

  */

  lpuartUserConfig.clockSource = kClockLpuartSrcPllFllSel;

  lpuartUserConfig.baudRate = 2000000;

  lpuartUserConfig.bitCountPerChar = kLpuart8BitsPerChar;

  lpuartUserConfig.parityMode = kLpuartParityDisabled;

  lpuartUserConfig.stopBitCount = kLpuartOneStopBit;

  eDmaUserConfig.chnArbitration = kEDMAChnArbitrationRoundrobin;

  EDMA_DRV_Init(&eDmaState, &eDmaUserConfig);

  /*

  * @ ToDo: allocate eDMA channel dynamically

  * both for lpuart transmit and receive

  * Channel 0 - LPUART RX

  * Channel 1 - LPUART TX

  */

  LPUART_DRV_EdmaInit(0, &lpuartEdmaState, &lpuartUserConfig);

  /*

  * re-initial RX to use eDMA + circular buffer

  */

    dmaBaseAddr = VIRTUAL_CHN_TO_EDMA_MODULE_REGBASE(lpuartEdmaState.edmaLpuartRx.channel);

    dmaChannel = VIRTUAL_CHN_TO_EDMA_CHN(lpuartEdmaState.edmaLpuartRx.channel);

    /* Setup destination */

    EDMA_HAL_HTCDSetDestAddr(dmaBaseAddr, dmaChannel, (uint32_t)(&g_ui8RxBuffer[0]));

    EDMA_HAL_HTCDSetDestOffset(dmaBaseAddr, dmaChannel, 1);

    EDMA_HAL_HTCDSetDestLastAdjust(dmaBaseAddr, dmaChannel, 0);

    /* Setup source */

    EDMA_HAL_HTCDSetSrcAddr(dmaBaseAddr, dmaChannel, LPUART_HAL_GetDataRegAddr(baseAddr));

    EDMA_HAL_HTCDSetSrcOffset(dmaBaseAddr, dmaChannel, 0);

    EDMA_HAL_HTCDSetSrcLastAdjust(dmaBaseAddr, dmaChannel, 0);

    /* Setup transfer properties */

    EDMA_HAL_HTCDSetNbytes(dmaBaseAddr, dmaChannel, 1);

    EDMA_HAL_HTCDSetChannelMinorLink(dmaBaseAddr, dmaChannel, 0, false);

    EDMA_HAL_HTCDSetMajorCount(dmaBaseAddr, dmaChannel, 1);

    EDMA_HAL_HTCDSetAttribute(dmaBaseAddr, dmaChannel, kEDMAModuloDisable, kEDMAModulo1Mbytes, kEDMATransferSize_1Bytes, kEDMATransferSize_1Bytes);

    EDMA_HAL_HTCDSetScatterGatherCmd(dmaBaseAddr, dmaChannel, false);

    EDMA_HAL_HTCDSetDisableDmaRequestAfterTCDDoneCmd(dmaBaseAddr, dmaChannel, false);

    /*

     * Finally, enable the LPUART receiver

     * Enable DMA trigger when receive data register full

     */

    LPUART_HAL_SetRxDmaCmd(baseAddr, true);

    LPUART_HAL_SetReceiverCmd(baseAddr, true);

}

B.R.

Jin Xin

0 Kudos