我如何使用 DMA 使用 CMSIS CORE 将源数组复制到目标数组?

How can i Use DMA to copy a source array to destination array Using CMSIS CORE?

我在 stm32f103rc 中尝试 DMA。我按照本教程 https://letanphuc.net/2014/06/how-to-use-stm32-dma/ 并使用 CMSIS CORE 编写了自己的代码。在这里,我使用两个数组,一个 'sourceArr',我在其中存储一个随机值,并在 DMA 的帮助下将该数组复制到 'destArr'。

DMA 相关函数定义和变量

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, 0);
}

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 */

}

主要

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)
    {

    }
}

如果一切正常,那么将有 5 次闪烁。 4 个在主函数中,1 个在 IRQ 中。

但我只眨了两下眼

任何建议都会很有帮助。

提前致谢

您应该设置要传输的数据数量

DMA1_Channel1->CNDTR = ARRAYSIZE;

在使用 DMA1_CHANNEL1_EN() 启用频道之前。

感谢大家的帮助。我得到了正确的答案。这是我的错误,因为我忘记设置要传输的数据数量。工作源代码是

#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, 0);
}

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)
    /*size of data to be transfered*/
    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
    }

谢谢大家