DMA使用

 内存到内存(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);
    }
    
    
}

### Linux DMA 使用示例 在 Linux 系统中,DMA(Direct Memory Access)是一种硬件机制,允许外设直接读取或写入系统内存而无需 CPU 干预。Xilinx 提供了一个名为 `xilinx_dma.h` 的头文件来支持其 AXI DMA IP 核的功能实现[^1]。 下面展示一个简单的 Xilinx DMA 驱动使用的例子: #### 初始化 DMA 设备 首先需要初始化 DMA 控制器并分配必要的资源。以下是伪代码形式的一个简单实例: ```c #include <linux/dma/xilinx_dma.h> static int dma_example_init(struct platform_device *pdev) { struct xilinx_dma_chan *chan; struct device *dev = &pdev->dev; chan = devm_kzalloc(dev, sizeof(*chan), GFP_KERNEL); if (!chan) return -ENOMEM; /* Initialize the channel */ init_xilinx_dma_channel(chan); /* Request and map memory regions */ if (dma_request_slave_channel(&pdev->dev, "tx") && dma_request_slave_channel(&pdev->dev, "rx")) { dev_err(dev, "Failed to request DMA channels\n"); return -ENODEV; } return 0; } ``` 上述代码片段展示了如何通过平台设备接口请求 DMA 通道,并完成基本的初始化工作[^1]。 #### 数据传输操作 一旦完成了 DMA 控制器的设置,就可以执行数据传输任务了。这里给出一段用于启动一次同步传输的操作示范: ```c struct dma_async_tx_descriptor *desc; u32 src_addr = 0x80000000; // 假定源地址 u32 dst_addr = 0xA0000000; // 假定目标地址 size_t len = PAGE_SIZE; /* Prepare a descriptor for transfer */ desc = dmaengine_prep_slave_single(dma_chan, src_addr, len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { pr_err("Failed to prepare slave single\n"); return -EINVAL; } /* Submit the transaction */ dma_cookie_t cookie = desc->tx_submit(desc); /* Issue pending transactions */ dma_async_issue_pending(dma_chan); // Wait until completion or timeout occurs. wait_for_completion_timeout(&completion, msecs_to_jiffies(100)); ``` 此部分实现了从指定物理地址向另一个位置拷贝固定长度的数据块功能[^1]。 关于 Initramfs 或 Ramdisk 的相关内容虽然提到过,但它主要用于构建临时根文件系统或者加载驱动模块等场景下辅助作用,并不是直接参与 DMA 流程的一部分[^2]。 --- 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值