5.6 DMA Guide

This chapter describes the file composition and the 12 public functions of the DMA driver in the N32G41x standard peripheral library: channel reset and initialization, peripheral and memory address and data-width configuration, channel and interrupt enabling, transfer-count read and write, flag and interrupt management, and request remapping. It also shows how the FLASH_RAM example moves data between FLASH and RAM in memory-to-memory mode. Read the DMA request mapping table and the register bit definitions together with the “DMA controller” chapter of the user manual, and take the errata sheet as the authority on known chip issues.

5.6.1 Related files

Relative path Purpose
firmware/n32g41x_std_periph_driver/inc/n32g41x_dma.h Defines the DMA_InitType structure and the macros for transfer direction, data width, priority, circular mode, memory-to-memory mode and request remapping, and declares 12 public functions in the six sections reset and initialization, channel enabling, configuration, read/write, interrupt and flag management, and request remapping
firmware/n32g41x_std_periph_driver/src/n32g41x_dma.c Implements those 12 functions: channel register reset and configuration, transfer-count and peripheral and memory address read and write, flag and interrupt status read and clear, and request remapping
projects/n32g41x_EVAL/examples/DMA/ DMA example root directory, containing 1 example, FLASH_RAM
projects/n32g41x_EVAL/examples/DMA/FLASH_RAM/ Directory composition of that example: MDK-ARM/, EWARM/, inc/, src/, readme.txt
projects/n32g41x_EVAL/bsp/ Board support files referenced by the example: the serial log init and print interface and the millisecond delay function

5.6.2 API reference

Search API12 functions

The following 12 public functions are listed in the declaration order of n32g41x_dma.h in 6 groups; each entry gives a summary and the original comment above the function in n32g41x_dma.c.

Reset and initialization

DMA_DeInit, DMA_Init, DMA_StructInit

Channel enabling

DMA_EnableChannel

Configuration

DMA_ConfigInt

Read/write

DMA_SetCurrDataCounter, DMA_GetCurrDataCounter

Interrupt and flag management

DMA_GetFlagStatus, DMA_ClearFlag, DMA_GetIntStatus, DMA_ClrIntPendingBit

Request remap

DMA_RequestRemap

void DMA_DeInit(DMA_ChannelType *DMAChx)Reset CHCFG, TXNUM, PADDR, MADDR, INTCLR registers of DMA Channel x to their default reset values.
Source comment
name    DMA_DeInit.
fun     Reset CHCFG, TXNUM, PADDR, MADDR, INTCLR registers of DMA Channel x
        to their default reset values.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
return  none

Use note: The implementation first clears the channel enable bit of DMA_CHCFGx, then clears CHCFG, TXNUM, PADDR and MADDR, and writes the interrupt mask of the corresponding channel to DMA_INTCLR to clear all its interrupt flags.

void DMA_Init(DMA_ChannelType *DMAChx, const DMA_InitType *DMA_InitParam)Initializes the DMA Channel x by the structure parameter DMA_InitParam of type DMA_InitType. Includes configuration peripheral/memory address, transmission direction, address increment mode, data bit width, priority, etc.
Source comment
name    DMA_Init.
fun     Initializes the DMA Channel x by the structure parameter
        DMA_InitParam of type DMA_InitType. Includes configuration
        peripheral/memory address, transmission direction, address
        increment mode, data bit width, priority, etc.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
param   DMA_InitParam (The input parameters must be the following values):
          - PeriphAddr
            -0x00000000~0xFFFFFFFF
          - MemAddr
            -0x00000000~0xFFFFFFFF
          - Direction
            - DMA_DIR_PERIPH_DST
            - DMA_DIR_PERIPH_SRC
          - BufSize
            -0x0000~0xFFFF
          - PeriphInc
            - DMA_PERIPH_INC_ENABLE
            - DMA_PERIPH_INC_DISABLE
          - DMA_MemoryInc
            - DMA_MEM_INC_ENABLE
            - DMA_MEM_INC_DISABLE
          - PeriphDataSize
            - DMA_PERIPH_DATA_SIZE_BYTE
            - DMA_PERIPH_DATA_SIZE_HALFWORD
            - DMA_PERIPH_DATA_SIZE_WORD
          - MemDataSize
            - DMA_MemoryDataSize_Byte
            - DMA_MemoryDataSize_HalfWord
            - DMA_MemoryDataSize_Word
          - CircularMode
            - DMA_MODE_CIRCULAR
            - DMA_MODE_NORMAL
          - Priority
            - DMA_PRIORITY_VERY_HIGH
            - DMA_PRIORITY_HIGH
            - DMA_PRIORITY_MEDIUM
            - DMA_PRIORITY_LOW
          - Mem2Mem
            - DMA_M2M_ENABLE
            - DMA_M2M_DISABLE
return  none

Use note: The implementation first reads DMA_CHCFGx and clears the bits defined by CCR_CLEAR_Mask (0xFFFF800F), then sets the configuration bits, and afterwards writes DMA_TXNUMx, DMA_PADDRx and DMA_MADDRx; apart from the masked bits, the channel enable bit and the interrupt enable bits are left unchanged.

void DMA_StructInit(DMA_InitType *DMA_InitParam)Initializes the structure parameter of type DMA_InitType used to initialize DMA. This function is usually called before initializing a parameter of type DMA_InitType.
Source comment
name    DMA_StructInit.
fun     Initializes the structure parameter of type DMA_InitType used to
        initialize DMA. This function is usually called before initializing
        a parameter of type DMA_InitType.
param   DMA_InitParam :
          - Pointer to the DMA_InitType structure which will be initialized.
return  none

Use note: The implementation sets PeriphAddr, MemAddr and BufSize to 0, Direction to DMA_DIR_PERIPH_SRC, the address increment, data width and circular mode to their disabled or smallest configuration, Priority to DMA_PRIORITY_LOW, and Mem2Mem to DMA_M2M_DISABLE.

void DMA_EnableChannel(DMA_ChannelType *DMAChx, FunctionalState Cmd)DMA Channel x Channel enable. This function is called after DMA initialization is successful to start moving data.
Source comment
name    DMA_EnableChannel.
fun     DMA Channel x Channel enable. This function is called after DMA
        initialization is successful to start moving data.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void DMA_ConfigInt(DMA_ChannelType *DMAChx, uint32_t DMAInt, FunctionalState Cmd)DMA Channel x interrupts enable. Before enabling a DMA channel, enabling transfer completion interrupt, half-transfer interrupt or transfer error interrupt will cause an interrupt when the corresponding event occurs.
Source comment
name    DMA_ConfigInt.
fun     DMA Channel x interrupts enable. Before enabling a DMA channel,
        enabling transfer completion interrupt, half-transfer interrupt
        or transfer error interrupt will cause an interrupt when the
        corresponding event occurs.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
param   DMAInt (The input parameters must be the following values):
          - DMA_INT_TXC
          - DMA_INT_HTX
          - DMA_INT_ERR
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void DMA_SetCurrDataCounter(DMA_ChannelType *DMAChx, uint16_t DataNumber)Set the current number of data transfers for DMA Channel x.
Source comment
name    DMA_SetCurrDataCounter.
fun     Set the current number of data transfers for DMA Channel x.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
param   DataNumber(The input parameters must be the following values) :
          - 0~0xFFFF
return  none
note    This function can only be used when the DMAChx is disabled.

Use note: The implementation writes DataNumber directly to DMA_TXNUMx; the source comment states that this function can only be used while the channel is disabled.

uint16_t DMA_GetCurrDataCounter(const DMA_ChannelType *DMAChx)Get the current number of remaining data for DMA Channel x.
Source comment
name    DMA_GetCurrDataCounter.
fun     Get the current number of remaining data for DMA Channel x.
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
return  Returns the number of data units remaining to be transferred.
FlagStatus DMA_GetFlagStatus(uint32_t DMAFlag, const DMA_Module *DMAy)Get DMA Channel x flag status. Contains the global flag, transfer completion flag, half-transfer flag, and transfer error flag for the corresponding channel.
Source comment
name    DMA_GetFlagStatus.
fun     Get DMA Channel x flag status. Contains the global flag, transfer
        completion flag, half-transfer flag, and transfer error flag for
        the corresponding channel.
param   DMAFlag (The input parameters must be the following values):
          - DMA_FLAG_GL1
          - DMA_FLAG_TC1
          - DMA_FLAG_HT1
          - DMA_FLAG_TE1
          - DMA_FLAG_GL2
          - DMA_FLAG_TC2
          - DMA_FLAG_HT2
          - DMA_FLAG_TE2
          - DMA_FLAG_GL3
          - DMA_FLAG_TC3
          - DMA_FLAG_HT3
          - DMA_FLAG_TE3
          - DMA_FLAG_GL4
          - DMA_FLAG_TC4
          - DMA_FLAG_HT4
          - DMA_FLAG_TE4
          - DMA_FLAG_GL5
          - DMA_FLAG_TC5
          - DMA_FLAG_HT5
          - DMA_FLAG_TE5
          - DMA_FLAG_GL6
          - DMA_FLAG_TC6
          - DMA_FLAG_HT6
          - DMA_FLAG_TE6
          - DMA_FLAG_GL7
          - DMA_FLAG_TC7
          - DMA_FLAG_HT7
          - DMA_FLAG_TE7
param   DMAy (The input parameters must be the following values):
          - DMA
return  SET or RESET.

Use note: The implementation reads DMA_INTSTS and ANDs it with DMAFlag; the DMA_FLAG_* macros are defined in the header as the clear bits of DMA_INTCLR, at the same bit positions as the status bits of DMA_INTSTS.

void DMA_ClearFlag(uint32_t DMAFlag, DMA_Module *DMAy)Clear DMA Channel x flag status. Contains the global flag, transfer completion flag, half-transfer flag, and transfer error flag for the corresponding channel.
Source comment
name    DMA_ClearFlag.
fun     Clear DMA Channel x flag status. Contains the global flag, transfer
        completion flag, half-transfer flag, and transfer error flag for the
        corresponding channel.
param   DMAFlag (The input parameters must be the following values):
          - DMA_FLAG_GL1
          - DMA_FLAG_TC1
          - DMA_FLAG_HT1
          - DMA_FLAG_TE1
          - DMA_FLAG_GL2
          - DMA_FLAG_TC2
          - DMA_FLAG_HT2
          - DMA_FLAG_TE2
          - DMA_FLAG_GL3
          - DMA_FLAG_TC3
          - DMA_FLAG_HT3
          - DMA_FLAG_TE3
          - DMA_FLAG_GL4
          - DMA_FLAG_TC4
          - DMA_FLAG_HT4
          - DMA_FLAG_TE4
          - DMA_FLAG_GL5
          - DMA_FLAG_TC5
          - DMA_FLAG_HT5
          - DMA_FLAG_TE5
          - DMA_FLAG_GL6
          - DMA_FLAG_TC6
          - DMA_FLAG_HT6
          - DMA_FLAG_TE6
          - DMA_FLAG_GL7
          - DMA_FLAG_TC7
          - DMA_FLAG_HT7
          - DMA_FLAG_TE7
param   DMAy (The input parameters must be the following values):
          - DMA
return  none.
INTStatus DMA_GetIntStatus(uint32_t DMA_IT, const DMA_Module *DMAy)Get DMA Channel x interrupt status. Contains the global interrupt, transfer completion interrupt, half-transfer interrupt, and transfer error interrupt for the corresponding channel.
Source comment
name    DMA_GetIntStatus.
fun     Get DMA Channel x interrupt status. Contains the global interrupt,
        transfer completion interrupt, half-transfer interrupt, and transfer
        error interrupt for the corresponding channel.
param   DMA_IT (The input parameters must be the following values):
          - DMA_INT_GLB1
          - DMA_INT_TXC1
          - DMA_INT_HTX1
          - DMA_INT_ERR1
          - DMA_INT_GLB2
          - DMA_INT_TXC2
          - DMA_INT_HTX2
          - DMA_INT_ERR2
          - DMA_INT_GLB3
          - DMA_INT_TXC3
          - DMA_INT_HTX3
          - DMA_INT_ERR3
          - DMA_INT_GLB4
          - DMA_INT_TXC4
          - DMA_INT_HTX4
          - DMA_INT_ERR4
          - DMA_INT_GLB5
          - DMA_INT_TXC5
          - DMA_INT_HTX5
          - DMA_INT_ERR5
          - DMA_INT_GLB6
          - DMA_INT_TXC6
          - DMA_INT_HTX6
          - DMA_INT_ERR6
          - DMA_INT_GLB7
          - DMA_INT_TXC7
          - DMA_INT_HTX7
          - DMA_INT_ERR7
param   DMAy (The input parameters must be the following values):
          - DMA
return  SET or RESET.
note    Global interrupt status is the logic or generation of transfer completion
        interrupt, half-transfer interrupt, transfer error interrupt.
void DMA_ClrIntPendingBit(uint32_t DMA_IT, DMA_Module *DMAy)Clear DMA Channel x interrupt status bits. Contains the global interrupt, transfer completion interrupt, half-transfer interrupt, and transfer error interrupt for the corresponding channel.
Source comment
name    DMA_ClrIntPendingBit.
fun     Clear DMA Channel x interrupt status bits. Contains the global interrupt,
        transfer completion interrupt, half-transfer interrupt, and transfer
        error interrupt for the corresponding channel.
param   DMA_IT (The input parameters must be the following values):
          - DMA_INT_GLB1
          - DMA_INT_TXC1
          - DMA_INT_HTX1
          - DMA_INT_ERR1
          - DMA_INT_GLB2
          - DMA_INT_TXC2
          - DMA_INT_HTX2
          - DMA_INT_ERR2
          - DMA_INT_GLB3
          - DMA_INT_TXC3
          - DMA_INT_HTX3
          - DMA_INT_ERR3
          - DMA_INT_GLB4
          - DMA_INT_TXC4
          - DMA_INT_HTX4
          - DMA_INT_ERR4
          - DMA_INT_GLB5
          - DMA_INT_TXC5
          - DMA_INT_HTX5
          - DMA_INT_ERR5
          - DMA_INT_GLB6
          - DMA_INT_TXC6
          - DMA_INT_HTX6
          - DMA_INT_ERR6
          - DMA_INT_GLB7
          - DMA_INT_TXC7
          - DMA_INT_HTX7
          - DMA_INT_ERR7
param   DMAy (The input parameters must be the following values):
          - DMA
return  none.
note    Global interrupt state is the logic or generation of transfer completion
        interrupt, half-transfer interrupt, transfer error interrupt. In fact,
        after clearing the three interrupt states, the global interrupt state
        will also be cleared.
void DMA_RequestRemap(uint32_t DMA_REMAP, const DMA_Module *DMAy, DMA_ChannelType *DMAChx, FunctionalState Cmd)Set DMA Channel x’s remap request. Channel request mapping is flexible, allowing users to map any DMA request to any DMA channel as needed. It is important to note that there can be only one DMA request per DMA channel at a time.
Source comment
name    DMA_RequestRemap.
fun     Set DMA Channel x's remap request. Channel request mapping is flexible,
        allowing users to map any DMA request to any DMA channel as needed. It
        is important to note that there can be only one DMA request per DMA
        channel at a time.
param   DMA_REMAP (The input parameters must be the following values):
          - DMA_REMAP_ADC1
          - DMA_REMAP_ADC2
          - DMA_REMAP_USART1_TX
          - DMA_REMAP_USART1_RX
          - DMA_REMAP_USART2_TX
          - DMA_REMAP_USART2_RX
          - DMA_REMAP_USART3_TX
          - DMA_REMAP_USART3_RX
          - DMA_REMAP_USART4_TX
          - DMA_REMAP_USART4_RX
          - DMA_REMAP_SPI1_TX
          - DMA_REMAP_SPI1_RX
          - DMA_REMAP_SPI2_TX
          - DMA_REMAP_SPI2_RX
          - DMA_REMAP_I2C1_TX
          - DMA_REMAP_I2C1_RX
          - DMA_REMAP_I2C2_TX
          - DMA_REMAP_I2C2_RX
          - DMA_REMAP_ATIM1_CH1
          - DMA_REMAP_ATIM1_CH2
          - DMA_REMAP_ATIM1_CH3
          - DMA_REMAP_ATIM1_CH4
          - DMA_REMAP_ATIM1_COM
          - DMA_REMAP_ATIM1_UP
          - DMA_REMAP_ATIM1_TRIG
          - DMA_REMAP_ATIM2_CH1
          - DMA_REMAP_ATIM2_CH2
          - DMA_REMAP_ATIM2_CH3
          - DMA_REMAP_ATIM2_CH4
          - DMA_REMAP_ATIM2_COM
          - DMA_REMAP_ATIM2_UP
          - DMA_REMAP_ATIM2_TRIG
          - DMA_REMAP_GTIM1_CH1
          - DMA_REMAP_GTIM1_CH2
          - DMA_REMAP_GTIM1_CH3
          - DMA_REMAP_GTIM1_CH4
          - DMA_REMAP_GTIM1_UP
          - DMA_REMAP_GTIM1_TRIG
          - DMA_REMAP_GTIM2_CH1
          - DMA_REMAP_GTIM2_CH2
          - DMA_REMAP_GTIM2_CH3
          - DMA_REMAP_GTIM2_CH4
          - DMA_REMAP_GTIM2_UP
          - DMA_REMAP_GTIM2_TRIG
          - DMA_REMAP_GTIM3_CH1
          - DMA_REMAP_GTIM3_CH2
          - DMA_REMAP_GTIM3_CH3
          - DMA_REMAP_GTIM3_CH4
          - DMA_REMAP_GTIM3_COM
          - DMA_REMAP_GTIM3_UP
          - DMA_REMAP_GTIM3_TRIG
          - DMA_REMAP_GTIM4_CH1
          - DMA_REMAP_GTIM4_CH2
          - DMA_REMAP_GTIM4_CH3
          - DMA_REMAP_GTIM4_CH4
          - DMA_REMAP_GTIM4_COM
          - DMA_REMAP_GTIM4_UP
          - DMA_REMAP_GTIM4_TRIG
          - DMA_REMAP_BIM1_UP
          - DMA_REMAP_BIM2_UP
param   DMAy (The input parameters must be the following values):
          - DMA
param   DMAChx (The input parameters must be the following values):
          - DMA_CH1
          - DMA_CH2
          - DMA_CH3
          - DMA_CH4
          - DMA_CH5
          - DMA_CH6
          - DMA_CH7
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none.

Use note: The implementation ignores the DMAy parameter and writes DMA_REMAP to CHSEL of DMAChx according to Cmd, writing the reserved value DMA_REMAP_NONE (0x3F) when Cmd is DISABLE; that reserved value is defined in the header but is not in the parameter list of the comment.

5.6.3 Demo descriptions

This section describes the 1 example of DMA: FLASH_RAM moves a constant array from FLASH to a RAM buffer in memory-to-memory mode and compares the two buffers after the transfer.

5.6.3.1 FLASH_RAM Memory-to-memory transfer

Example directory: projects/n32g41x_EVAL/examples/DMA/FLASH_RAM/

Enable the DMA clock and set up the serial log→configure DMA channel 1 for a memory-to-memory transfer→map the channel request to a reserved source→enable the transfer-complete interrupt and start the channel→set the completion flag in the transfer-complete interrupt→compare the source and destination buffers and print the result

Item Source analysis
Function Uses DMA in memory-to-memory mode to move a 32-word constant array from FLASH to a RAM buffer, then compares the source and destination buffers with memcmp and prints a pass message over the serial port when they match.
Source files src/main.c: main, RCC_Configuration, NVIC_Configuration, DMA_IRQ_HANDLER and the constant array;
inc/main.h: the channel, clock, interrupt and buffer-size macros;
src/n32g41x_it.c, inc/n32g41x_it.h: exception and SysTick handlers;
readme.txt: function, environment and usage;
MDK-ARM/, EWARM/: Keil and IAR projects.
The log interface log_init, log_info and log_error comes from bsp/inc/log.h.
Key configuration Channel DMA_CH1 with clock RCC_AHB_PERIPH_DMA;
PeriphAddr points to SRC_Const_Buffer in FLASH and MemAddr points to DST_Buffer in RAM, direction DMA_DIR_PERIPH_SRC, BufSize is BUFFER_SIZE (32);
both the peripheral and the memory address increment, both data widths are word, normal mode, high priority, Mem2Mem enabled;
the request is remapped to a reserved source;
the interrupt is DMA_INT_TXC1 with NVIC preemption and sub-priority both 0 and IRQ number DMA_CH1_IRQn. The system clock is HSI+PLL, 80 MHz on the N32G412 and 96 MHz on the N32G415.
Program and data path main calls log_init;
RCC_Configuration enables the DMA clock and NVIC_Configuration enables the DMA interrupt;
after memset clears DST_Buffer, DMA_StructInit loads the defaults and DMA_Init writes the channel registers;
DMA_RequestRemap maps the request to a reserved source, DMA_ConfigInt enables the transfer-complete interrupt and DMA_EnableChannel starts the channel;
main polls until the interrupt sets TransferCompleteFlag, then the two buffers are compared and the result printed.
Main APIs DMA_DeInit, DMA_StructInit, DMA_Init, DMA_RequestRemap, DMA_ConfigInt, DMA_EnableChannel, DMA_GetIntStatus, DMA_ClrIntPendingBit
Verification After compiling, downloading and resetting, the serial port first prints DMA Flash to RAM demo go...;
when the transfer completes and the check matches it prints DMA Flash to RAM passed, otherwise DMA Flash to RAM failed.
Use note The clock source is HSI+PLL, 80 MHz on the N32G412 and 96 MHz on the N32G415;
the serial port uses PA9 for TX and PA10 for RX at 115200 bps;
the development environment is KEIL MDK-ARM V5.34 or IAR EWARM 8.50.1.
Core-code walkthrough and porting

The example selects the DMA channel and buffer size with one group of macros, fills DMA_InitType, starts a memory-to-memory transfer, and lets the transfer-complete interrupt notify the main program to check the result.

Data path: SRC_Const_Buffer (FLASH) -> the PeriphAddr and MemAddr fields of DMA_InitStructure -> DMA_Init writes PADDR, MADDR and TXNUM of DMA_CH1 -> the transfer-complete interrupt sets TransferCompleteFlag -> memcmp compares DST_Buffer -> the result is printed over the serial port

1. Define the channel and buffer size with macros. inc/main.h groups the channel, clock, interrupt and buffer length into one set of macros that the rest of the code references by name.

inc/main.hinc/main.h
#define DMA_USED           DMA
#define DMA_CLK            RCC_AHB_PERIPH_DMA
#define DMA_CHANNEL_USED   DMA_CH1
#define DMA_IRQ_HANDLER    DMA_CH1_IRQHandler
#define DMA_IT_FLAG_TC     DMA_INT_TXC1
#define DMA_IT_FLAG_GL     DMA_INT_GLB1
#define DMA_IRQN           DMA_CH1_IRQn

#define BUFFER_SIZE (sizeof(SRC_Const_Buffer) / sizeof(SRC_Const_Buffer[0]))

extern const uint32_t SRC_Const_Buffer[];

When moving to another channel or changing the transfer length, only this group of macros changes; the configuration and the interrupt handler in main stay the same.

2. Fill DMA_InitType and write the channel registers. main first resets the channel with DMA_DeInit and loads the defaults with DMA_StructInit, then sets the source and destination addresses, direction, buffer length, address increment, data widths, circular mode, priority and the memory-to-memory bit field by field, and finally DMA_Init writes them.

src/main.csrc/main.c · main
    DMA_DeInit(DMA_CHANNEL_USED);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr     = (uint32_t)SRC_Const_Buffer;
    DMA_InitStructure.MemAddr        = (uint32_t)DST_Buffer;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = BUFFER_SIZE;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_ENABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_WORD;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Word;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_ENABLE;
    DMA_Init(DMA_CHANNEL_USED, &DMA_InitStructure);

The direction is DMA_DIR_PERIPH_SRC, so the PeriphAddr side is the source; both peripheral and memory data widths are word, so no width alignment is performed while they match.

3. Map the request first, then enable the interrupt and the channel. In memory-to-memory mode the example maps the channel request to a reserved source, enables the transfer-complete interrupt, and finally enables the channel to start the transfer.

src/main.csrc/main.c · main
    DMA_RequestRemap(DMA_REMAP_NONE, DMA, DMA_CHANNEL_USED, ENABLE);

    DMA_ConfigInt(DMA_CHANNEL_USED, DMA_INT_TXC, ENABLE);
    DMA_EnableChannel(DMA_CHANNEL_USED, ENABLE);

The DMA_REMAP_NONE passed to DMA_RequestRemap is the reserved request value defined in the header; for a peripheral-triggered transfer this must be changed to the corresponding DMA_REMAP_* source.

4. The interrupt sets the completion flag and the main program compares the buffers. The transfer-complete interrupt reads and clears the completion flag of channel 1 and sets TransferCompleteFlag; after the wait loop the main program compares the source and destination buffers with memcmp.

src/main.csrc/main.c · DMA_IRQ_HANDLER
void DMA_IRQ_HANDLER(void)
{
    if (DMA_GetIntStatus(DMA_IT_FLAG_TC, DMA_USED))
    {
        DMA_ClrIntPendingBit(DMA_IT_FLAG_TC, DMA_USED);
        TransferCompleteFlag = 1;
    }
}
src/main.csrc/main.c · main
    while (TransferCompleteFlag == 0) {}

    if (memcmp(SRC_Const_Buffer, DST_Buffer, sizeof(SRC_Const_Buffer)) == 0)
    {
        log_info("DMA Flash to RAM passed\n");
    }
    else
    {
        log_error("DMA Flash to RAM failed\n");
    }

DMA_INT_TXC1 and DMA_IT_FLAG_TC refer to the transfer-complete interrupt of channel 1; when another channel is used, DMA_IT_FLAG_TC, DMA_IRQN and the interrupt handler name must be changed to that channel’s macros and handler.

Corresponding source files: src/main.c, inc/main.h

5.6.4 Notes and troubleshooting

Scenario Check & action Source
Moving data to FLASH with DMA Chapter 7 of the user manual states that DMA must not be used to program FLASH, to avoid timing errors;
a memory-to-memory transfer involving FLASH only reads, and FLASH writing is done by other means.
User manual
Request mapping in memory-to-memory mode The user manual says that when a channel is configured for memory-to-memory mode its request selection value must be set to a reserved value (for example 63);
the channel configuration flow requires the MEM2MEM bit to be configured first and the channel to be enabled last.
User manual
Interrupt state before enabling the channel The interrupt description in the user manual requires all interrupts of that channel to be cleared before the channel is enabled;
an interrupt status bit is cleared by writing 1 to the corresponding bit of the clear register.
User manual
Writing registers after the channel is enabled DMA_TXNUMx is read-only once the channel is enabled, and DMA_PADDRx and DMA_MADDRx can be written only while the channel is disabled (DMA_CHCFGx.CHEN is 0);
disable the channel before changing these registers.
User manual
Turning off circular mode The user manual says circular mode is turned off by writing 0 to DMA_CHCFGx.CHEN to disable the channel and then writing 0 to CIRC;
while the channel is enabled the other bits of DMA_CHCFGx cannot be rewritten.
User manual
Several channels sharing one request source The request mapping notes in the user manual state that different channels must not use the same request source, otherwise only the higher-priority channel is triggered when several channels are enabled. User manual
Alignment when the data widths differ When DMA_CHCFGx.PSIZE and DMA_CHCFGx.MSIZE differ, DMA aligns the data according to the programmable data width table of the user manual;
to write an 8-bit register at a 32-bit address boundary, set the peripheral size to 8 bits and the memory size to 32 bits.
User manual

The N32G412 and N32G415 series errata sheet V1.0.0 (2026.6.30) lists a single row for revision A chips with an empty errata link column, and gives no DMA-related entries.

Nations Technologies DevKit Docs

Datasheets, SDK, driver APIs and demo guides for Nations Technologies MCU development kits, organized by chip series.

© 2026 Nations Technologies Inc. All rights reserved.粤ICP备11069485号This site uses cookie-free anonymous analytics.