cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 DMA large block transfer

tg.developer
Associate II
Posted on January 21, 2014 at 09:41

Hello to all,

I am writing application which uses peripheral to memory DMA transfer. When transfers are

smaller than 65535 items written in NDTR register everything is working fine.To be able to support large piece of data transfer I have modified DMA interrupt handler like this:

void DMA2_Stream1_IRQHandler(void)

{   

    /* DMA Transfer Complete Interrupt */

    if(DMA_GetITStatus(DMA2_Stream1, DMA_IT_TCIF1)) 

    {

        DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);

        if(pic_frame_size > 0)

        {

          DMA_Cmd(DMA2_Stream1, DISABLE);

          while((DMA_GetCmdStatus(DMA2_Stream1)) != DISABLE);

          if(pic_frame_size <= 65532)

            DMA_InitStructure.DMA_BufferSize = pic_frame_size;

          else

            DMA_InitStructure.DMA_BufferSize = 65532;

  

          pic_frame_size_proc = DMA_InitStructure.DMA_BufferSize;

          pic_frame_size -= pic_frame_size_proc; 

          g_dma_cycle++;

          

          DMA_InitStructure.DMA_Memory0BaseAddr = (buffer + (SDRAM_DMA_ADDR_BLOCK * g_dma_cycle));

          DMA_Init(DMA2_Stream1, &DMA_InitStructure);

          DMA_Cmd(DMA2_Stream1, ENABLE);         

          while((DMA_GetCmdStatus(DMA2_Stream1)) != ENABLE);

        }else

          tx_ready = 1;

    }else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_HTIF1)) 

    {

    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_HTIF1);

    }else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_TEIF1)) 

    {

    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TEIF1);

    }else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_DMEIF1)) 

    {

      DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_DMEIF1);

    }else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_FEIF1)) 

    {

    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_FEIF1);

    }

}

Data are transferred to the external 16 bit wide SDRAM, while peripheral is 32 bit wide.

The problem I am experiencing is, that DMA_IT_TCIF1 is set even NDTR register is not 0,

what is stated in data sheets and also observed when number of items are less then 65535. 

The second interrupt which happens is  DMA_IT_HTIF1, which should not happen. 

I done DMA setup like this:

    DMA_InitStructure.DMA_Channel = DMA_Channel_1; 

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

    pic_frame_size = FRAME_BUFFER_SIZE/4;

    if(pic_frame_size <= 65532)

      DMA_InitStructure.DMA_BufferSize = pic_frame_size;

    else

      DMA_InitStructure.DMA_BufferSize = 65532;

  

    pic_frame_size_proc = DMA_InitStructure.DMA_BufferSize;

    pic_frame_size -= pic_frame_size_proc;

    DMA_InitStructure.DMA_Memory0BaseAddr = buffer;

    DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDR;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA2_Stream1, &DMA_InitStructure);

Could be something wrong with DMA setup?

I will appreciate any help.

2 REPLIES 2
Posted on January 22, 2014 at 09:19

> DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

The DMA controller is tricky, and behind the DMA_SxNDTR register are in fact a couple of registers, one the counter itself, and other a shadow register holding the value last written to it. There are cases when the counter gets reloaded from the shadow register. As with the rest of the documentation, this is not as clearly described as it may be, but there are hints:

- RM0090 rev 5, description of DMA_SxNDTR register on  p.328:

Once the transfer has completed, this register can either stay at zero (when the stream is in

normal mode) or be reloaded automatically with the previously programmed value in the

following cases:

– when the stream is configured in Circular mode.

– when the stream is enabled again by setting EN bit to '1'

- RM0090 rev.6, 10.3.14 DMA transfer suspension, p.317:

[after suspension, DMA_SxNDTR has to be read, and in order to restart...] The SxNDTR register has to be updated with the remaining number of data items to be transferred (the value read when the stream was disabled)

JW
tg.developer
Associate II
Posted on January 22, 2014 at 17:36

thanks for a hint. It helped a lot.