Begining with DMA stm32

Thread Starter

devjeetmandal

Joined May 7, 2017
48
I was trying DMA in stm32f103rc. I followed this tutorial https://letanphuc.net/2014/06/how-to-use-stm32-dma/ and wrote my own code using CMSIS CORE. Here i m taking two arrays one 'sourceArr' where i am storing a random value and copying that array to 'destArr' with the help of DMA.

DMA RELATED FUNCTIONS DEFINES AND VARIABLES

C:
volatile uint32_t status = 0;
  uint32_t sourceArr[ARRAYSIZE];
  uint32_t destArr[ARRAYSIZE];
   
  #define DMA1_CLOCK_EN()     (RCC->AHBENR = RCC_AHBENR_DMA1EN)
  #define DMA1_CHANNEL1_EN()   (DMA1_Channel1->CCR |= DMA_CCR1_EN)  //((uint16_t)0x0001)
   
  void DMA1_Channel1_IRQHandler(void)
  {
     if (DMA1->ISR & DMA_ISR_TCIF1)
     {
       status = 1;
       Blink_Led(5000);
       DMA1->IFCR |= DMA_IFCR_CTCIF1;
     }
  }
   
  void NVIC_Init()
  {
      NVIC_EnableIRQ(DMA1_Channel1_IRQn);
      NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
  }
   
  void DMA_Init(void)
  {
     DMA1_Channel1->CCR |= DMA_CCR1_MEM2MEM;  /*Memory to memory transfer enable  ((uint16_t)0x4000)*/
     DMA1_Channel1->CCR &= ~DMA_CCR1_CIRC;         /* circular mode* ((uint16_t)0x0020) */
     /* Priroty set as medium PL[1:0] = 01 */
     DMA1_Channel1->CCR |= DMA_CCR1_PL_0;  //((uint16_t)0x1000)
     /* source and destination data size set as 32bit */
     DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_1;  //((uint16_t)0x0800)
     DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_1;  //((uint16_t)0x0200)
     /* Auto increment of memory enabled for source and destination */
     DMA1_Channel1->CCR |= DMA_CCR1_PINC;  //((uint16_t)0x0040)
     DMA1_Channel1->CCR |= DMA_CCR1_MINC;  //((uint16_t)0x0080)
     /* Data transfer direction set as read from peripheral*/
     DMA1_Channel1->CCR &= ~DMA_CCR1_DIR;  //((uint16_t)0x0010)
     /* source and destination start addresses */
     DMA1_Channel1->CPAR = (uint32_t)&sourceArr;
     DMA1_Channel1->CMAR = (uint32_t)&destArr;
     /* Enable DMA1 Channel Transfer Complete interrupt */
  DMA1_Channel1->CCR |= DMA_CCR1_TCIE;    //((uint16_t)0x0002)
     
  }
   
  void DMA_DeInit(void)
  {
     DMA1_Channel1->CCR &= (uint16_t)~DMA_CCR1_EN;   /* Disable the selected DMAy Channelx */
     DMA1_Channel1->CCR = 0;                         /* Reset DMAy Channelx control register */
     DMA1_Channel1->CNDTR = 0;                       /* Reset DMAy Channelx remaining bytes register */
     DMA1_Channel1->CPAR = 0;                       /* Reset DMAy Channelx peripheral address register */
     DMA1_Channel1->CMAR = 0;                       /* Reset DMAy Channelx memory address register */
     DMA1->IFCR   |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;     /* Reset interrupt pending bits for DMA1 Channel1 */
   
  }
[B]
MAIN

C:
[/B]


  int main(void)
  {
     int i;
     for (i=0;i<ARRAYSIZE;i++)
       sourceArr[i] = i;
     Led_Init();
     Blink_Led(1000);
     DMA1_CLOCK_EN();     //enable clock for DMA
     DMA_DeInit();
     DMA_Init();
     NVIC_Init();
     Blink_Led(1000);
     status = 0;
     DMA1_CHANNEL1_EN();  //Enable DMA1 Channel 1 transfer
     while(status==0);
     Blink_Led(1000);
     for (i=0; i<ARRAYSIZE;i++)
  {
  destArr[i]=sourceArr[i];
  }
     Blink_Led(1000);
       
     while (1)
     {
       
     }
  }

if everything works fine then there will be 5 Blinks. 4 in the main function and 1 in IRQ.

But i am only getting two blinks.

Any suggestions will be really helpful.

Thanks in Advance


 

MrChips

Joined Oct 2, 2009
34,807
You will have to explain in more detail what is supposed to happen in your program.
Where is ARRAYSIZE defined?
What DMA operation are you attempting to perform?
Peripheral to peripheral?
Peripheral to memory?
Memory to peripheral?
Memory to memory?
 

Thread Starter

devjeetmandal

Joined May 7, 2017
48
ARRAYSIZE is defined as 100

What DMA operation are you attempting to perform?
I am doing memory to memory operations.

Doubt(if i m doing wrong):
And I will create two array one source and another destination and copy that using DMA. What DMA operation should i perform?
Can you provide a real life example for all these operations.?

Is my DMA_Init() function is correct for memory to memory DMA operations?
I think i m doing wrong somewhere in the function.

https://letanphuc.net/2014/06/how-to-use-stm32-dma/
I have followed this link(to be precise the comments) to writhe my code.

SOURCE CODE

C:
#include "stm32f10x.h"

#define ARRAYSIZE     100

#define LED_PORT_EN()       ( RCC->APB2ENR |= RCC_APB2ENR_IOPDEN )
#define LED_PORT           GPIOD

#define LED_MODE_BIT1       8
#define LED_MODE_BIT2       9
#define LED_CNF_BIT1       10
#define LED_CNF_BIT2       11


#define CNF_SET_PORTD(BIT1,BIT2)       (   LED_PORT->CRL &= ~((1<<BIT1) | (1<<BIT2)) )   //General purpose output push-pull
#define MODE_SET_PORTD(BIT1,BIT2)       ( LED_PORT->CRL |=  (1<<BIT1) | (1<<BIT2) )     //Output mode, max speed 50 MHz.

#define SET_GPIO_BIT_PORTD(BIT)         ( LED_PORT->BSRR =   (1 << BIT) )               //For setting the Bit   
#define RESET_GPIO_BIT_PORTD(BIT)       ( LED_PORT->BSRR =   ( (1 << BIT) << 16 )   )     //For Resseting Bit

volatile uint32_t status = 0;
uint32_t sourceArr[ARRAYSIZE];
uint32_t destArr[ARRAYSIZE];

#define DMA1_CLOCK_EN()       (RCC->AHBENR |= RCC_AHBENR_DMA1EN)
#define DMA1_CHANNEL1_EN()   (DMA1_Channel1->CCR |= DMA_CCR1_EN)  //((uint16_t)0x0001)
void Delay(int ms);
void Led_Init(void);
void Blink_Led(int ms);
void DMA_DeInit(void);
void DMA_Init(void);
void NVIC_Init(void);
void DMA1_Channel1_IRQHandler(void);
int main(void)
{
   int i;
   for (i=0;i<ARRAYSIZE;i++)
     sourceArr[i] = i;
   Led_Init();
   Blink_Led(1000);
   DMA1_CLOCK_EN();     //enable clock for DMA
   DMA_DeInit();
   DMA_Init();
   NVIC_Init();
   Blink_Led(1000);
   status = 0;
   __enable_irq();
   DMA1_CHANNEL1_EN();  //Enable DMA1 Channel 1 transfer
   while(status==0);
   Blink_Led(1000);
   for (i=0; i<ARRAYSIZE;i++)
  {
  destArr[i]=sourceArr[i];
  }
   Blink_Led(1000);
     
   while (1)
   {
     
   }
}

void DMA1_Channel1_IRQHandler(void)
{
   if (DMA1->ISR & DMA_ISR_TCIF1)
   {
     status = 1;
     Blink_Led(5000);
     DMA1->IFCR |= DMA_IFCR_CTCIF1;
   }
}

void NVIC_Init()
{
    NVIC_EnableIRQ(DMA1_Channel1_IRQn);
    NVIC_SetPriority(DMA1_Channel1_IRQn, 1);
}

void DMA_Init(void)
{
   DMA1_Channel1->CCR |= DMA_CCR1_MEM2MEM;  /*Memory to memory transfer enable  ((uint16_t)0x4000)*/
   DMA1_Channel1->CCR &= ~DMA_CCR1_CIRC;         /* circular mode* ((uint16_t)0x0020) */
   /* Priroty set as medium PL[1:0] = 01 */
   DMA1_Channel1->CCR |= DMA_CCR1_PL_0;  //((uint16_t)0x1000)
   /* source and destination data size set as 32bit */
   DMA1_Channel1->CCR |= DMA_CCR1_MSIZE_1;  //((uint16_t)0x0800)
   DMA1_Channel1->CCR |= DMA_CCR1_PSIZE_1;  //((uint16_t)0x0200)
   /* Auto increment of memory enabled for source and destination */
   DMA1_Channel1->CCR |= DMA_CCR1_PINC;  //((uint16_t)0x0040)
   DMA1_Channel1->CCR |= DMA_CCR1_MINC;  //((uint16_t)0x0080)
   /* Data transfer direction set as read from peripheral*/
   DMA1_Channel1->CCR &= ~DMA_CCR1_DIR;  //((uint16_t)0x0010)
   DMA1_Channel1->CNDTR = ARRAYSIZE;
   /* source and destination start addresses */
   DMA1_Channel1->CPAR = (uint32_t)sourceArr;
   DMA1_Channel1->CMAR = (uint32_t)destArr;
   /* Enable DMA1 Channel Transfer Complete interrupt */
  DMA1_Channel1->CCR |= DMA_CCR1_TCIE;    //((uint16_t)0x0002)
   
}

void DMA_DeInit(void)
{
   DMA1_Channel1->CCR &= (uint16_t)~DMA_CCR1_EN;   /* Disable the selected DMAy Channelx */
   DMA1_Channel1->CCR = 0;                         /* Reset DMAy Channelx control register */
   DMA1_Channel1->CNDTR = 0;                       /* Reset DMAy Channelx remaining bytes register */
   DMA1_Channel1->CPAR = 0;                       /* Reset DMAy Channelx peripheral address register */
   DMA1_Channel1->CMAR = 0;                       /* Reset DMAy Channelx memory address register */
   DMA1->IFCR   |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;     /* Reset interrupt pending bits for DMA1 Channel1 */

}


/** @breif: For wait and doing nothing i.e for delay
    * @param: delaya time
    * @retVal: None
  */
   void Delay(int ms)
   {
     int i,j;
     for (i = 0; i < ms; ++i) {
       for (j = 0; j < 5000; ++j);
       }
   }


/** @breif: Initalize GPIO For Led
    * @param: None
    * @retVal: None
  */
   
   
   void Led_Init()
   {
     LED_PORT_EN();                                 //Enable RCC for Led Port
     CNF_SET_PORTD(LED_CNF_BIT1,LED_CNF_BIT2);       //SET CNF     General purpose output push-pull
     MODE_SET_PORTD(LED_MODE_BIT1,LED_MODE_BIT2);   //SET MODE  Output mode, max speed 50 MHz.
   }

   
/** @breif: Blink Led Placed in PORT D Pin 2
    * @param: Delay for each state(ON/OFF)
    * @retVal: None
  */

   void Blink_Led(int ms)
   {
     RESET_GPIO_BIT_PORTD(2);             //Make Led High
     Delay(ms);                           //wait
     SET_GPIO_BIT_PORTD(2);               //Make Led Low
     Delay(ms);                           //wait
   }
i am waiting for DMA to do things by its own and set the status variable. then i m trying to copy by using CPU, to measure the time difference. I don't know where i m going wrong.

Thanks a lot for your reply.
 
Last edited:

Thread Starter

devjeetmandal

Joined May 7, 2017
48
I have found whats going wrong.. I did not set the number of data to be transferred i.e
DMA1_Channel1->CNDTR = ARRAYSIZE;
Thank you MrChips. This are working just fine :)
 
Top