DMA使用

文章详细介绍了GD32F30x单片机中DMA0Channel0、3和4的配置,涉及内存到内存传输、内存到外设发送和外设到内存接收的功能,以及中断处理和USART通信的集成。

 内存到内存(dma基础配置)

#include "gd32f30x.h" 

void DMA0_Channel0_IRQHandler(){
    if( dma_interrupt_flag_get(DMA0,DMA_CH0,DMA_INT_FLAG_FTF) ){
        dma_interrupt_flag_clear(DMA0,DMA_CH0,DMA_INT_FLAG_FTF);
    }
}
    
int main(){
    static const unsigned char data0[10] = {1,2,3,4,5,6,7,8,9,10};
    unsigned char data1[10] = {0};

    rcu_periph_clock_enable(RCU_DMA0);
    dma_deinit(DMA0,DMA_CH0);
    dma_memory_to_memory_enable(DMA0,DMA_CH0);
    
    dma_parameter_struct dmaCfg;
    dma_struct_para_init(&dmaCfg);
    dmaCfg.periph_addr  = data0;
    dmaCfg.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; 
    dmaCfg.periph_inc   = DMA_PERIPH_INCREASE_ENABLE;
    dmaCfg.memory_addr  = data1;
    dmaCfg.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dmaCfg.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dmaCfg.number       = 10;
    dmaCfg.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dmaCfg.priority     = DMA_PRIORITY_LOW;
    dma_init(DMA0,DMA_CH0,&dmaCfg);
    
    dma_interrupt_enable(DMA0,DMA_CH0,DMA_INT_FLAG_FTF);
    nvic_irq_enable(DMA0_Channel0_IRQn,2,2);
    
    dma_circulation_enable(DMA0,DMA_CH0);
    dma_channel_enable(DMA0,DMA_CH0);
    
    while(1){
    }
    
    
}

内存到外设(发送)

#include "gd32f30x.h" 


dma_parameter_struct dmaTxCfg;

volatile int dmaSending = 0;
void DMA0_Channel3_IRQHandler(){
    if( dma_interrupt_flag_get(DMA0,DMA_CH3,DMA_INT_FLAG_FTF) ){
        dma_interrupt_flag_clear(DMA0,DMA_CH3,DMA_INT_FLAG_FTF);
        dmaSending = 0;
    }
}

void UsartDmaSend(unsigned char* pData, int nLen){
    while( dmaSending );
    dmaSending = 1;
    dma_channel_disable(DMA0,DMA_CH3);
    dmaTxCfg.memory_addr  = pData;
    dmaTxCfg.number       = nLen;
    dma_init(DMA0,DMA_CH3,&dmaTxCfg);
    dma_channel_enable(DMA0,DMA_CH3);
}


void UsartDmaCfg(){
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_9);
    
    rcu_periph_clock_enable(RCU_USART0);
    usart_deinit(USART0);
    usart_baudrate_set(USART0,115200);
    usart_parity_config(USART0,USART_PM_NONE);
    usart_word_length_set(USART0,USART_WL_8BIT);
    usart_stop_bit_set(USART0,USART_STB_1BIT);
    usart_transmit_config(USART0,USART_TRANSMIT_ENABLE);
    usart_dma_transmit_config(USART0,USART_TRANSMIT_DMA_ENABLE);//重点
    usart_enable(USART0);
    
    rcu_periph_clock_enable(RCU_DMA0);
    dma_deinit(DMA0,DMA_CH3);

    dma_struct_para_init(&dmaTxCfg);
    dmaTxCfg.periph_addr  = USART0+0x04;
    dmaTxCfg.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; 
    dmaTxCfg.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dmaTxCfg.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dmaTxCfg.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dmaTxCfg.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dmaTxCfg.priority     = DMA_PRIORITY_LOW;
    
    dma_interrupt_enable(DMA0,DMA_CH3,DMA_INT_FTF);
    nvic_irq_enable(DMA0_Channel3_IRQn,2,2);
    dma_init(DMA0,DMA_CH3,&dmaTxCfg);

}


int main(){

    UsartDmaCfg();
    while(1){
        UsartDmaSend("123",3);
    }
    
    
}

外设到内存(接收)

#include "gd32f30x.h" 

dma_parameter_struct dmaTxCfg;
dma_parameter_struct dmaRxCfg;

volatile int dmaSending = 0;
void DMA0_Channel3_IRQHandler(){
    if( dma_interrupt_flag_get(DMA0,DMA_CH3,DMA_INT_FLAG_FTF) ){
        dma_interrupt_flag_clear(DMA0,DMA_CH3,DMA_INT_FLAG_FTF);
        dmaSending = 0;
    }
}
void UsartDmaSend(unsigned char* pData, int nLen){
    dmaSending = 1;    
    dma_channel_disable(DMA0,DMA_CH3);
    dmaTxCfg.memory_addr  = pData;
    dmaTxCfg.number       = nLen;
    dma_init(DMA0,DMA_CH3,&dmaTxCfg);
    dma_channel_enable(DMA0,DMA_CH3);
    while( dmaSending );
}
#define RECV_BUF_LEN  128
unsigned char UsartReceiveBuffer[RECV_BUF_LEN]={0};
void DMA0_Channel4_IRQHandler(){
    if( dma_interrupt_flag_get(DMA0,DMA_CH4,DMA_INT_FLAG_FTF) ){
        dma_interrupt_flag_clear(DMA0,DMA_CH4,DMA_INT_FLAG_FTF);
        
        dma_channel_disable(DMA0,DMA_CH4);
        dma_init(DMA0,DMA_CH4,&dmaRxCfg);
        dma_channel_enable(DMA0,DMA_CH4);//关掉再开启,达到循环接收(或使用循环模式(不推荐))
        
        UsartDmaSend(UsartReceiveBuffer,RECV_BUF_LEN);//收满128个再发
    }
}
void USART0_IRQHandler(){
    if( usart_interrupt_flag_get(USART0,USART_INT_FLAG_IDLE) ){
        usart_interrupt_flag_clear(USART0,USART_INT_FLAG_IDLE);//不再有数据进来会触发空闲中断
        usart_data_receive(USART0);//触发空闲中断后读一下,否则会一直触发空闲中断
        
        int n = RECV_BUF_LEN - dma_transfer_number_get(DMA0,DMA_CH4);//从number向下计数
        
        dma_channel_disable(DMA0,DMA_CH4);
        dma_init(DMA0,DMA_CH4,&dmaRxCfg);
        dma_channel_enable(DMA0,DMA_CH4);
        
        UsartDmaSend(UsartReceiveBuffer,n);
    }
}
void UsartDmaCfg(){
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_6);
    gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_10MHZ,GPIO_PIN_7);
    gpio_pin_remap_config(GPIO_USART0_REMAP,ENABLE);
    
    rcu_periph_clock_enable(RCU_USART0);
    usart_deinit(USART0);
    usart_baudrate_set(USART0,115200);
    usart_parity_config(USART0,USART_PM_NONE);
    usart_word_length_set(USART0,USART_WL_8BIT);
    usart_stop_bit_set(USART0,USART_STB_1BIT);
    usart_transmit_config(USART0,USART_TRANSMIT_ENABLE);
    usart_receive_config(USART0,USART_RECEIVE_ENABLE);
    usart_dma_transmit_config(USART0,USART_TRANSMIT_DMA_ENABLE);
    usart_dma_receive_config(USART0,USART_RECEIVE_DMA_ENABLE);
    usart_interrupt_enable(USART0,USART_INT_IDLE);//使能空闲中断
    nvic_irq_enable(USART0_IRQn,2,2);
    usart_enable(USART0);
    
    rcu_periph_clock_enable(RCU_DMA0);
    dma_deinit(DMA0,DMA_CH3);
    dma_struct_para_init(&dmaTxCfg);
    dmaTxCfg.periph_addr  = USART0+0x04;
    dmaTxCfg.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; 
    dmaTxCfg.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dmaTxCfg.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dmaTxCfg.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dmaTxCfg.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dmaTxCfg.priority     = DMA_PRIORITY_LOW;
    dma_interrupt_enable(DMA0,DMA_CH3,DMA_INT_FTF);
    nvic_irq_enable(DMA0_Channel3_IRQn,0,2);
//由于发送相关的中断服务函数中包含发送函数,会导致发送相关的函数中断无法执行,需将其抢断优先级调高
    dma_init(DMA0,DMA_CH3,&dmaTxCfg);
    
    dma_deinit(DMA0,DMA_CH4);
    dma_struct_para_init(&dmaRxCfg);
    dmaRxCfg.periph_addr  = USART0+0x04;
    dmaRxCfg.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; 
    dmaRxCfg.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dmaRxCfg.memory_addr  = UsartReceiveBuffer;
    dmaRxCfg.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dmaRxCfg.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dmaRxCfg.number       = RECV_BUF_LEN;
    dmaRxCfg.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dmaRxCfg.priority     = DMA_PRIORITY_LOW;
    dma_interrupt_enable(DMA0,DMA_CH4,DMA_INT_FTF);
    nvic_irq_enable(DMA0_Channel4_IRQn,2,2);
    dma_init(DMA0,DMA_CH4,&dmaRxCfg);
    dma_channel_enable(DMA0,DMA_CH4);//接收时一开始就要开启使能
}


int main(){

    UsartDmaCfg();
    while(1){
        //UsartDmaSend("123",3);
    }
    
    
}

DMA(直接内存访问)是一种绕过CPU直接在设备和内存之间传输数据的机制。其使用方法与具体应用场景和硬件平台相关,下面分别从基本原理中的通用概念和STM32平台为例进行介绍。 ### 通用DMA使用步骤 从基本原理角度,典型的DMA传输涉及设备、DMA控制器和内存,并且需要CPU进行配置。通用的DMA使用步骤如下: 1. **CPU配置**:CPU需要对DMA控制器进行初始化配置,包括设置传输的源地址(设备或内存)、目标地址(内存或设备)、传输数据的长度、传输方向等参数,以确保DMA控制器知道如何进行数据传输。 2. **启动传输**:配置完成后,CPU启动DMA传输过程,将控制权交给DMA控制器。 3. **DMA传输**:DMA控制器接管数据传输工作,在设备和内存之间直接进行数据传输,此过程不需要CPU参与。 4. **传输完成处理**:当DMA传输完成后,可能会触发中断通知CPU,CPU可以进行后续的处理工作,如数据处理、状态更新等。 ### STM32平台DMA使用方法 在STM32平台上,使用DMA还需要考虑其工作特点和相关寄存器的配置: 1. **配置传输地址**:STM32中的DMA_CPARx、DMA_CMARx可以存放外设的地址或内存的地址,可根据实际需求进行配置。 2. **满足传输条件**:DMA进行数据传输需要满足必要条件,即剩余传输数据量大于0、DMA通道传输使能以及通道上有DMA数据传输事件请求。在使用时,需要确保这些条件都得到满足。 以下是一个简单的STM32 DMA配置示例代码(伪代码): ```c #include "stm32xxxx.h" void DMA_Configuration(void) { DMA_InitTypeDef DMA_InitStructure; // 使能DMA时钟 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 配置DMA通道 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&PERIPHERAL_ADDRESS; // 外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&MEMORY_ADDRESS; // 内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 传输方向 DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; // 传输数据长度 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 初始化DMA通道 DMA_Init(DMA1_Channelx, &DMA_InitStructure); // 使能DMA通道 DMA_Cmd(DMA1_Channelx, ENABLE); } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值