Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1166286
  • 博文数量: 173
  • 博客积分: 4048
  • 博客等级:
  • 技术积分: 2679
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-12 18:53
文章分类

全部博文(173)

文章存档

2018年(1)

2016年(1)

2013年(1)

2012年(118)

2011年(52)

分类: 嵌入式

2011-12-07 14:58:17

关于DMA传输的实验。

    在系统运行时,当需要传输大量数据时,可以采用DMA的方式进行传输,以解脱出CPU来处理其他命令。

打开DMA时一般同时设定其传输位数:

//打开发送通道
    tx1 = alt_dma_txchan_open("/dev/dma_0");
    alt_dma_txchan_ioctl(tx1, ALT_DMA_SET_MODE_32,NULL);

//打开接收通道
    rx1 = alt_dma_rxchan_open("/dev/dma_2");
    alt_dma_rxchan_ioctl(rx1, ALT_DMA_SET_MODE_32,NULL);

nios总线address是按32位编址的,对32位以内的寻址由4位的byteenable来决定,每位表示32位中1字节。

       Nios II中的DMA传输有以下三种形式:

1、 存储器到存储器

这种情况下需要同时打开发送通道和接收通道,而且源地址和目标地址都是自增的。

//打开发送通道

tx = alt_dma_txchan_open("/dev/dma_0");

//tx_buf是源地址、传输数据块长度是length字节

dma_res = alt_dma_txchan_send(tx, tx_buf, length, NULL, NULL);

//打开接收通道

rx = alt_dma_rxchan_open("/dev/dma_0");

//rx_buf是目标地址、传输数据块长度是length、dma_done()是DMA完成后被调用的回调函数,handle为其void *类型的参数。

dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, handle); 

 

2、 存储器到外设

这种情况下只要打开发送通道,而且源地址是自增的,目标地址是固定的。

tx = alt_dma_txchan_open("/dev/dma_0"); // 打开发送通道

alt_dma_txchan_ioctl(tx, ALT_DMA_TX_ONLY_ON, (void *)dst_addr); // dst_addr是目标地址

dma_res = alt_dma_txchan_send(tx, tx_buf, length, dma_done, NULL); // tx_buf是源地址

 

3、 外设到存储器

这种情况下只要打开接收通道,而且源地址是固定的,目标地址是自增的。

rx = alt_dma_rxchan_open("/dev/dma_0"); // 打开接收通道

alt_dma_rxchan_ioctl(rx, ALT_DMA_RX_ONLY_ON, (void *)source_addr); // source_addr是源地址

dma_res = alt_dma_rxchan_prepare(rx, rx_buf, length, dma_done, NULL); // rx_buf是目标地址

 

其中通过alt_dma_txchan_ioctl,alt_dma_rxchan_ioctl还可以设置每次发送和接收的字节数。

 

以下是基于DMA通过UART发送和接收数据的例子,注意DMA_0 为接受通道,DMA_1为发送通道。当然可以将dma的read_master和writer_master同时连在uart_0和sdram_0的从端 口上,这样是可以用一个dma对两者读写操作,但是不能同时做双向传输。

#include
#include
#include "system.h"
#include "sys/alt_dma.h"
#include "unistd.h"

int main(void)
{/*
    alt_dma_rxchan rx;
    //创建DMA接收信道
    rx = alt_dma_rxchan_open("/dev/dma_0");
    //当信道创建成功
    if(rx != NULL)
    {
        printf("Dma transition start.");
        while(1)
        {
            //设置DMA传输的数据位宽 本例中为8位
            alt_dma_rxchan_ioctl(rx,ALT_DMA_SET_MODE_8,NULL);
            //指定从uart接收数据
            alt_dma_rxchan_ioctl(rx,ALT_DMA_RX_ONLY_ON,(void*)UART_0_BASE);
           
            //提交DMA接收请求 指定接收数据的位置(sdram)以及传输数据量
            if(alt_dma_rxchan_prepare(rx,
                                       SDRAM_0_BASE,
                                       1024,
                                       NULL,
                                       NULL) < 0)
            {
                printf ("Error: failed to post receive request\n");
            }
            //关闭DMA接收信道
            alt_dma_rxchan_close(rx);
            usleep(1000000);
        }
    }
   
   */
    alt_dma_txchan  tx;
    tx = alt_dma_txchan_open("/dev/dma_1");
     if(tx != NULL)
    {
        printf("Dma transition start.");
    while(1)
        {   
            alt_dma_txchan_ioctl(tx,ALT_DMA_SET_MODE_8,NULL);
            alt_dma_txchan_ioctl(tx,ALT_DMA_TX_ONLY_ON,(void*)(UART_0_BASE+2));

          //注意是UART_0_BASE+2,因为UART的txdata寄存器在rxdata之后,偏移量为一个rxdata的长度(16位,2个字节)
                if(alt_dma_txchan_send(tx,
                                       SDRAM_0_BASE,
                                       1024,
                                       NULL,
                                      (void*) NULL) < 0)
            {
                printf ("Error: failed to post transmit request\n");
            }
            //关闭DMA发送信道
            alt_dma_txchan_close(tx);
            usleep(1000000);
        }
    }
    return 0;
}

阅读(5383) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~