1
votes

I am using an STM32F103, attempting to copy from one array to another using DMA. The transfer works the first time and a breakpoint in DMA1_Channel1_IRQHandler is hit, but subsequent calls to DMA_Cmd(DMA1_Channel1, ENABLE) have no effect and the breakpoint is not hit. Error flag DMA1_FLAG_TE1 is not set. Is there something additional which needs to be set/reset for the transfer to run a second time?

#include "stm32f10x.h"

#define ARRAYSIZE 800
volatile uint32_t status = 0;
volatile uint32_t i;


int main(void)
{
    uint32_t source[ARRAYSIZE];
    uint32_t destination[ARRAYSIZE];
    for (i=0; i<ARRAYSIZE;i++)
        source[i]=i;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_InitTypeDef  DMA_InitStructure;
    DMA_DeInit(DMA1_Channel1);

    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)source;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)destination;

    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    status = 1;

    while (1)
      {
        if(status == 1)
        {
           status = 0;

           DMA1_Channel1->CNDTR = ARRAYSIZE;
           DMA1_Channel1->CPAR = (uint32_t)source;
           DMA1_Channel1->CMAR = (uint32_t)destination;
           DMA_ClearFlag(DMA1_FLAG_GL1);
           DMA_ClearFlag(DMA1_FLAG_TC1);

           DMA_Cmd(DMA1_Channel1, DISABLE);
           DMA_Cmd(DMA1_Channel1, ENABLE);
        }
      }
}

void DMA1_Channel1_IRQHandler(void)
{
  if(DMA_GetITStatus(DMA1_IT_TC1))
  {
    status=1;
    DMA_ClearITPendingBit(DMA1_IT_GL1);
  }
}
1
You're setting status to 0 in if block, your program won't enter it second time. Do you want to have continuous, circular DMA transfer or start it in your own?rkrahl
I haven't noticed setting of status in isr, first part of previous comment is not relevant anymore.rkrahl

1 Answers

3
votes

Disable DMA before setting its registers and enable it afterwards. According to RM0008 (page 287) DMA_CNDTRx can only be written when the channel is disabled. The same goes for DMA_CMARx.