• 基于Nios II的DMA传输

    2013-03-25 20:06:24
    在系统运行时,当需要传输大量数据时,可以采用DMA的方式进行传输,以解脱出CPU来处理其他命令。    Nios II中的DMA传输有以下三种形式: 1、 存储器到存储器 这种情况下需要同时打开发送通道和接收...

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

     

           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完成后被调用的回调函数

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

     

    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 <stdio.h>
    #include <string.h>
    #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;
    }

    展开全文
  • Nios II 中的DMA

    2011-08-21 10:32:34
    转载地址:http://www.china-vision.net/blog/user1/6/archives/2006/200696122323.html 有了上一讲HAL的基础,我们来关注一下DMANIOS 中的实现和编程。DMA是个老问题了,从8086/8088一
    
    

    转载地址:http://www.china-vision.net/blog/user1/6/archives/2006/200696122323.html


    有了上一讲HAL的基础,我们来关注一下DMANIOS 中的实现和编程。DMA是个老问题了,从8086/8088一直到现在,完成不需要CPU参与的数据搬家,源和目标可以是内存也可以是设备,在NIOS II中通过基于HAL编程完成。
      
    下图是三中基本的DMA传输:

     NIOS IIHAL DMA设备模式中,DMA传输被分为两类:transmit  receiveNIOS提供两种设备驱动实现transmit channelsreceive channelstransmit channels把缓冲区数据发送到目标设备,receive channels读取设备数据存放到缓冲区。

    DMA的概念其实挺简单,无非就是把一定长度的数据从源地址传送到目标地址。其中有一点比较重要的是对于地址的操作方式,一种是地址自增,另一种是地址固定。就是说DMA控制器读或写完一个数据后,对地址是自动增加,下次读写下一个地址,还是不变,下次还是读写同一个地址。由于地址固定模式一般是用在外设,所以在Nios的文档中,使用地址固定模式的一方就称为设备(Peripheral),而使用地址自增模式的一方则称为内存(Memory)。
       为了适应大家不同的开发环境,下面我们完成一个相对简单的DMA操作,复制SDRAM内存缓冲区到on_chip_memory中,如果我们在库工程属性中设置了SDRAM为主内存,那么程序中分配的数组缓冲区就在SDRAM中,我们用指针赋值让指针指向on_chip_memory。这个操作完全可以在程序中用memcpy来实现,我们趋简就繁,就是为了尝试一下DMAJ
       
    首先我们在SOPC Builder中增加一个名字为dma_0DMA设备。两个表单设置都选默认。

     第二步,DMA设备有三个PORT,两个MASTER PORT:read_masterwrite_master,一个SLAVE PORT:control_port_slave。需要在SOPC BUILDER中设置AVALONE交换总线,设置read_mastersdram连接,write_masteron_chip_memory连接,具体见下图(交叉点为黑色)

    sopc builder中生成系统,并在Quartus II中编译下载,硬件部分就OK了。如果你的DMA操作不是内存到内存的,而是内存到设备,或者设备到内存,那么你需要在上面这一步中加以设置,设备只支持读写,是CPU读写还是DMA读写设备不加以区分。
    在程序中,我们要使用DMA必须包含:sys/alt_dma.h
    因为是内存DMA操作,所以我们必须实现transmit channelsreceive channels,这在NIOS II中就是打开两个设备。在NIOS II IDE中生成一个以Hello World为模板的memory_dma工程项目修改一下程序如下:

    #i nclude <stdio.h>
    #i nclude <stdlib.h>
    #i nclude <sys/alt_dma.h>
    #i nclude "system.h"
    static volatile int rx_done = 0;
    /*
    *   Callback function that obtains notification that the data has
    *   been received.
    */
    static void done (void* handle, void* data)
    {
      rx_done++;
    }
    int main (int argc, char* argv[], char* envp[])
    {
      int rc;
      static char buff[256];
      alt_dma_txchan txchan;
      alt_dma_rxchan rxchan;
      void* tx_data = (void*) buff;                 /* pointer to data to send */
      void* rx_buffer = (void*) 0x01000000; /* on_chip_memory addr*/
      
      /* Create the transmit channel */
      if ((txchan = alt_dma_txchan_open("/dev/dma_0")) == NULL)
      {
        printf ("Failed to open transmit channel\n");
        exit (1);
      }
      /* Create the receive channel */
      if ((rxchan = alt_dma_rxchan_open("/dev/dma_0")) == NULL)
      {
        printf ("Failed to open receive channel\n");
        exit (1);
      }
      /* Post the transmit request */
      if ((rc = alt_dma_txchan_send (txchan,
                                      tx_data,
                                      128,
                                      NULL,
                                      NULL)) < 0)
      {
        printf ("Failed to post transmit request, reason = %i\n", rc);
        exit (1);
      }
      
      /* Post the receive request */
      if ((rc = alt_dma_rxchan_prepare (rxchan,
                                        rx_buffer,
                                        128,
                                        done,
                                        NULL)) < 0)
      {
        printf ("Failed to post read request, reason = %i\n", rc);
        exit (1);
      }
       
       
       /* wait for transfer to complete */
        while (!rx_done);
            printf ("Transfer successful!\n");
        return 0;
    }


    我们很多人对DMA理解的很深入,在其他嵌入式领域有丰富的经验,在其他系统上的实现问题很自然会想在NIOS II中是怎么完成的呢,比如DMA完成以后需要中断吗?如何知道DMA传输完成等等,在上面的程序中,实际上是通过回调函数完成的,回调函数在Windows系统的WIN API中以及驱动开发中被大量使用。
       
    好了,DMA就是如此,还有一些相关的函数需要去尝试一下。尝试非常重要,在资料欠缺的时候,需要创建环境去实验,你的理解是这样的,按这样的理解会有这样的结果,实际做一下到底是怎样的,不符合?是理解错了吗?不断尝试,收益无限

    展开全文
  • 今天一个哥们问我DMA传输,他用我上一篇关于DMA串口传输的程序,因为他没怎么学过所以我给他讲不通,而且他根本不了解串口怎么连接!所以想做个DMA的存储器之间的传输。 下面的图是SOPC连接图,其中dma_0为上次...

          今天一个哥们问我DMA的传输,他用我上一篇关于DMA串口传输的程序,因为他没怎么学过所以我给他讲不通,而且他根本不了解串口怎么连接!所以想做个DMA的存储器之间的传输。

          下面的图是SOPC连接图,其中dma_0为上次的串口和SDRAM传输控制,注意上次讲错了——因为DMA是可以双向传输,即读写端口可以同时连载要传输的两个设备上。dma_1为这次要用到的,分别连到SDRAM和ON_CHIP_MEM上,其实可以不用ON_CHIP_MEM的,即DMA可以完成同一存储器之间不同地址的传输。

    2010060819390075.jpg

          下面是NIOS II C++源程序

    #include <stdio.h>
    #include <string.h>
    #include "system.h"
    #include "sys/alt_dma.h"
    #include "unistd.h"
    #include "altera_avalon_uart_regs.h"
    #include "io.h"
    #include <sys/alt_cache.h>
    static volatile int tx_done = 0;
    //回调函数
    
    static void done (void* handle)
    {
    tx_done++;
    }
    #define TRANSFER_LENGTH 128
    int main(void)
    {
        
        char *source = (void*)(SDRAM_0_BASE+10000);
        char *dest = (void*)(ON_CHIP_MEM_BASE+256);
        memset(source,0x54,TRANSFER_LENGTH);
           
        alt_dma_txchan tx;
        //创建DMA发送信道
        tx = alt_dma_txchan_open("/dev/dma_1");
        //当信道创建成功
        if(tx == NULL)
        {
            printf("Failed to open transit channel.\n");
        }
        else
        {
            printf("Create the transit channel successfully.\n");
        }
        
        //创建DMA接收通道  
        alt_dma_rxchan  rx;
        rx = alt_dma_rxchan_open("/dev/dma_1");
        //当信道创建成功
         if(rx == NULL)
        {
            printf("Failed to open receive channel.\n");
        }
        else
        {
            printf("Create the receive channel successfully.\n");
        }        
       
         if(alt_dma_txchan_send(tx, 
                                source, 
                                TRANSFER_LENGTH, 
                                NULL, 
                                NULL)<0)
            {
            printf ("Error: failed to post transmit request\n");
            }
                                       
        
        //提交DMA接收请求 指定接收数据的位置(sdram)以及传输数据量
        if(alt_dma_rxchan_prepare(rx, 
                                  dest, 
                                  TRANSFER_LENGTH, 
                                  done, 
                                  NULL) < 0)
            {
            printf ("Error: failed to post receive request\n");
            }
            
    // 等待发送结束
    while (!tx_done);
    
    printf("Transmit successful\n");
    
    usleep(5000000);
    int loop,errorcount=0;
    for(loop=1;loop<TRANSFER_LENGTH;loop++)
    {
        //对比缓冲区数据
        if(source[loop]!=dest[loop])
        {
            printf("Verify failed at location: 0x%X\n",loop);
            errorcount++;
        }
    }
    if(errorcount==0)
    {
        printf("Transfer successfully !\n");
    }
    else
    {
        printf("Transfer failed !\n");
    }
    
    while(1);
    }
    
         需要注意的是:DMA传输数据长度必须是2的N次方(2^N),否则会出现错误的,另外可能由于SDRAM数据同步问题,如果接收数据的是SDRAM上的内存空间,结果会打印:Transfer failed !即,在比较两个空间数据时会出现不相等,但是调试的时候是可以,虽然我做了延时5秒钟,但是还是不能解决,希望高手解答!如果接收数据的是ON_CHIP_MEM的话是完全没有问题的。

    本人个人主页本文地址:http://jrmen.org.ru/archives/31

    转载于:https://www.cnblogs.com/menjr/archive/2010/06/08/1754253.html

    展开全文
  • NIOS2 DMA 传输模式

    2018-12-31 19:24:02
    http://blog.ednchina.com/chactor/185802/message.aspx Nios II中的DMA传输有以下三种形式: 1、 存储器到存储器 这种情况下需要同时打开发送通道和接收通道,而且源地址和目标地址都是自增的。 tx = alt_dma_...

    5 1 3 4

    http://blog.ednchina.com/chactor/185802/message.aspx

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

    1、 存储器到存储器

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

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

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

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

    dma_res = alt_dma_rxchan_prepare(rx, rx_buf, 32, dma_done, NULL); // rx_buf是目标地址,dma_done()是DMA完成后被调用的回调函数。

     

    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, 32, 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, 32, dma_done, NULL); // rx_buf是目标地址

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

    展开全文
  • 最近练了一段时间的DMA传输,现做如下的总结,分享自己获得心得以及遇到的一些问题。 在系统运行时,当需要传输大量数据时,可以采用DMA的方式进行传输,以解脱出... Nios II中的DMA传输有以下三种形式: 1、...

    转载:http://blog.ednchina.com/chactor/185802/message.aspx#92932

     

    最近练了一段时间的DMA传输,现做如下的总结,分享自己获得心得以及遇到的一些问题。

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


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

    1、  存储器到存储器

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

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

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

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

    dma_res = alt_dma_rxchan_prepare(rx, rx_buf, 32, dma_done, NULL); // rx_buf是目标地址,dma_done()DMA完成后被调用的回调函数。

     

    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, 32, 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, 32, dma_done, NULL);  // rx_buf是目标地址

     

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


           下面给出两个实例,说明DMA传输的过程。

     

    1、  存储器到存储器

    下面程序为SDRAMonchip-memory的数据传输。

    硬件连接图示:

    点击看大图

    程序如下:

    #include <stdio.h>

    #include <stdlib.h>

    #include <sys/alt_dma.h>

    #include "system.h"

    static volatile int rx_done = 0;

    int rc;

    alt_dma_txchan txchan;

    alt_dma_rxchan rxchan;

    static char buff[256];

    void* tx_data = (void*) buff; /* 源地址 */

    void* rx_buffer = (void*) 0x01801000; /* 目标地址,从上图看到0x01801000onchip-memory的地址*/

    //DMA传输结束回调函数

    static void done_t(void* handle, void* data)

    {

       

        rx_done++;

       

    }

     

    int main (int argc, char* argv[], char* envp[])

    {

     

    /* 打开发送通道 */

      if ((txchan = alt_dma_txchan_open("/dev/dma")) == NULL)

      {

        printf ("Failed to open transmit channel\n");

        exit (1);

      }

    /* 打开接收通道 */

      if ((rxchan = alt_dma_rxchan_open("/dev/dma")) == NULL)

      {

        printf ("Failed to open receive channel\n");

        exit (1);

      }

    /* 开始发送数据 */

      if ((rc = alt_dma_txchan_send (txchan,

                                     tx_data,

                                     128,

                                     NULL,

                                     NULL)) < 0)

      {

        printf ("Failed to post transmit request, reason = %i\n", rc);

        exit (1);

      }

    /* 开始接收数据*/

      if ((rc = alt_dma_rxchan_prepare (rxchan,

                                        rx_buffer,

                                        128,

                                        done_t,

                                        NULL)) < 0)

      {

        printf ("Failed to post read request, reason = %i\n", rc);

        exit (1);

      }

    /* 等待传输结束 */

      while (!rx_done);

      printf ("Transfer successful!\n");

     

      return 0;

    }

    程序运行结束后在Nios IDEconsole界面中显示:

    Transfer successful!

    表明传输成功。

     

    2、  存储器到UART

    下面程序为SDRAMUART的数据传输

    硬件连接图:

    点击看大图

    程序如下:

    #include <stdio.h>

    #include <stdlib.h>

    #include "sys/alt_dma.h"

    #include "altera_avalon_uart_regs.h"

    #include "system.h"

    #include "alt_types.h"

     

    static volatile int tx_done = 0;

    volatile static alt_u8 chr[20] = {1,2,3,4,6,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20} ;//待发送的数据

    //回调函数

    static void done (void* handle)

    {

    tx_done++;

    }

    int main()

    {

    int rc;

    alt_dma_txchan txchan;

     

    void* source_buff_ptr = (void*) chr; /* 源地址 */

    void* destination_buff_ptr = (void*)IOADDR_ALTERA_AVALON_UART_TXDATA(UART_BASE); /* 目标地址IOADDR_ALTERA_AVALON_UART_TXDATA(UART_BASE)函数读出txdata的地 */

     

    /* 打开发送通道 */

    if ((txchan = alt_dma_txchan_open("/dev/dma")) == NULL)

    {

    printf ("Failed to open transmit channel\n");

    exit (1);

    }

    /* 设置目标地址固定 */

    if ((rc = alt_dma_txchan_ioctl(txchan, ALT_DMA_TX_ONLY_ON, destination_buff_ptr)) < 0)

    {

    printf ("Failed to set ioctl, reason = %i\n", rc);

    exit (1);

    }

    //设置每次发送一个字节,即8位,因为UART每次只发送8

    if((rc = alt_dma_txchan_ioctl(txchan,ALT_DMA_SET_MODE_8 ,NULL))<0)

    {

        printf("Failed to set mode 8\n");

        exit(1);

    }

    /* 开始发送 */

    if ((rc = alt_dma_txchan_send(txchan, source_buff_ptr, 20, done, NULL)) < 0)

    {

    printf ("Failed to post transmit request, reason = %i\n", rc);

    exit (1);

    }

    /* 等待发送结束 */

    while (!tx_done);

    printf ("Transfer successful!\n");

    return 0;

    }

    不过该程序执行结束后,在串口调试器中显示Transfer successful!却没有显示DMA发送的那20个数字。不知道哪里需要修改,放在这里和大家讨论下。

    转载于:https://www.cnblogs.com/kongtiao/archive/2011/09/23/2185783.html

    展开全文
  • Nios II中的DMA传输

    2013-03-28 20:49:02
    Nios II中的DMA传输有以下三种形式: 1、 存储器到存储器 这种情况下需要同时打开发送通道和接收通道,而且源地址和目标地址都是自增的。 tx = alt_dma_txchan_open("/dev/dma_0");//打开发送通道 dma_...
  • NIOS2随笔——DMA(1)

    2019-06-16 05:14:57
    1. NIOS2 DMA控制器结构框图与其它IP外设一样,...2. NIOS2 DMA三种传输方式3. NIOS2 DMA API函数NIOS2 DMA的API函数原型都定义在alt_dma.h头文件中,常用的API函数如下:alt_dma_txchanalt_dma_txchan_open(const...
  •   关于DMA传输的实验。 在系统运行时,当需要传输大量数据时,可以采用DMA的方式进行传输,以...Nios II中的DMA传输有以下三种形式: 1、 存储器到存储器 这种情况下需要同时打开发送通道和接收通道,而且源...
  • 在 Quartus7.2之后的版本中,除了原有的基于avalon-mm总线的DMA之外,还增加了Scatter-Gather DMA这种基于avalon-ST流总线的DMA IP核,它更适合与大量数据流传输的场合,使用起来比较灵活,增加了与外设流器件配合的...
  • Nios II 下的DMA传输

    2019-07-13 08:58:46
    DMA(Direct Memory Access)直接存储器传输,是指将外设的数据不经过微处理器直接传送到存储器中,或者,从存储器不经过微处理器直接将数据传送至外部设备。一次DMA传输只需要执行一个DMA周期(相当于一个总线时钟...
  • Nios II DMA: 多次发起

    2018-12-31 19:24:45
    转载:... 第二次发起可以在第一次DMA传输没有结束的情况下开始,不过要注意,两次的目标地址不能有重叠部分,否则发起会失败。 #include &lt;stdio.h&gt;...
1 2 3 4 5 ... 8
收藏数 141
精华内容 56
热门标签