MPSOC 在linux下实现axi_dma数据读写

概述

  • 之前的文章分享了如何在裸跑的情况下实现AXI_DMA回环测试(有需要的可以翻看之前的文章),也分享过如何通过mmap函数映射的方式操作片内外设。接下来就在之前两篇文章的基础上聊一下在linux下如何实现axi_dma数据读写。

框图

  • 实现框图如下所示
    在这里插入图片描述

  • block design框图如下所示
    在这里插入图片描述

  • Address map分配如下所示
    在这里插入图片描述

代码实现(废话不多说直接上干货)

  • axi_dma.h
#ifndef _AXI_DMA__H
#define _AXI_DMA__H

/***************************** Include Files *********************************/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/mman.h>

/************************** Constant Definitions *****************************/
#define MM2S_CR_OFFSET           ((0x00000000) >> 2)   /**< Channel control */
#define MM2S_SR_OFFSET           ((0x00000004) >> 2)   /**< Status */
#define MM2S_CDESC_OFFSET        ((0x00000008) >> 2)   /**< Current descriptor pointer */
#define MM2S_CDESC_MSB_OFFSET    ((0x0000000C) >> 2)   /**< Current descriptor pointer */
#define MM2S_TDESC_OFFSET        ((0x00000010) >> 2)   /**< Tail descriptor pointer */
#define MM2S_TDESC_MSB_OFFSET    ((0x00000014) >> 2)   /**< Tail descriptor pointer */
#define MM2S_SRCADDR_OFFSET      ((0x00000018) >> 2)   /**< Simple mode source address pointer */
#define MM2S_SRCADDR_MSB_OFFSET  ((0x0000001C) >> 2)   /**< Simple mode source address pointer */
#define MM2S_DESTADDR_OFFSET     ((0x00000018) >> 2)   /**< Simple mode destination address pointer */
#define MM2S_DESTADDR_MSB_OFFSET ((0x0000001C) >> 2)   /**< Simple mode destination address pointer */
#define MM2S_BUFFLEN_OFFSET      ((0x00000028) >> 2)   /**< Tail descriptor pointer */
#define MM2S_SGCTL_OFFSET        ((0x0000002c) >> 2)   /**< SG Control Register */

#define S2MM_CR_OFFSET           ((0x00000000 + 0x30) >> 2)   /**< Channel control */
#define S2MM_SR_OFFSET           ((0x00000004 + 0x30) >> 2)   /**< Status */
#define S2MM_CDESC_OFFSET        ((0x00000008 + 0x30) >> 2)   /**< Current descriptor pointer */
#define S2MM_CDESC_MSB_OFFSET    ((0x0000000C + 0x30) >> 2)   /**< Current descriptor pointer */
#define S2MM_TDESC_OFFSET        ((0x00000010 + 0x30) >> 2)   /**< Tail descriptor pointer */
#define S2MM_TDESC_MSB_OFFSET    ((0x00000014 + 0x30) >> 2)   /**< Tail descriptor pointer */
#define S2MM_SRCADDR_OFFSET      ((0x00000018 + 0x30) >> 2)   /**< Simple mode source address pointer */
#define S2MM_SRCADDR_MSB_OFFSET  ((0x0000001C + 0x30) >> 2)   /**< Simple mode source address pointer */
#define S2MM_DESTADDR_OFFSET     ((0x00000018 + 0x30) >> 2)   /**< Simple mode destination address pointer */
#define S2MM_DESTADDR_MSB_OFFSET ((0x0000001C + 0x30) >> 2)   /**< Simple mode destination address pointer */
#define S2MM_BUFFLEN_OFFSET      ((0x00000028 + 0x30) >> 2)   /**< Tail descriptor pointer */

#define XAXIDMA_PHY_ADDR            0x80000000
#define SRC_PHY_ADDR                0x10000000
#define DES_PHY_ADDR                0x20000000


/**************************** Type Definitions *******************************/

typedef struct
{
    off_t phy_addr;

    unsigned int *v_base_addr;
    unsigned int *src;
    unsigned int *des;

    unsigned int rd_len;
    unsigned int wt_len;

}xdma_handle;



/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/

/************************** Variable Definitions *****************************/
void xdma_test();
unsigned int copy_from_pl(xdma_handle *xdma);
unsigned int copy_to_pl(xdma_handle *xdma);
void axi_dma_init();
#endif
  • axi_dma.c
#include "axi_dma.h"
xdma_handle xdma_hd;

unsigned int axi_dma_write(unsigned int* dma_base_addr, int reg_offset, unsigned int value) 
{
    dma_base_addr[reg_offset] = value;
    return 1;
}

unsigned int axi_dma_read(unsigned int* dma_base_addr, int reg_offset)
{
    return dma_base_addr[reg_offset];
}

void axi_dma_reset(unsigned int* dma_base_addr)
{
    /*<! reset the channels */
    axi_dma_write(dma_base_addr, MM2S_CR_OFFSET, 4);
    axi_dma_write(dma_base_addr, S2MM_CR_OFFSET, 4);

    /*<! halt the channels */
    axi_dma_write(dma_base_addr, MM2S_CR_OFFSET, 0);
    axi_dma_write(dma_base_addr, S2MM_CR_OFFSET, 0);
}

void axi_dma_init()
{
    int dh = open("/dev/mem", O_RDWR | O_SYNC); 

    xdma_handle *xdma = &xdma_hd;
    xdma->v_base_addr= mmap(NULL, 
                            65535, 
                            PROT_READ|PROT_WRITE, 
                            MAP_SHARED, 
                            dh, 
                            XAXIDMA_PHY_ADDR); 
    xdma->src = mmap(NULL, 
                     65535, 
                     PROT_READ|PROT_WRITE, 
                     MAP_SHARED, 
                     dh, 
                     SRC_PHY_ADDR);

    xdma->des = mmap(NULL, 
                     65535, 
                     PROT_READ|PROT_WRITE, 
                     MAP_SHARED, 
                     dh, 
                     DES_PHY_ADDR);

    xdma->rd_len = 512;
    xdma->wt_len = 512;

    //
    // 
    // printf(" - Source address : 0x%x \r\n", xdma->src); 
    // printf(" - Destination address: 0x%x\r\n",xdma->des);
    // 
    //

    axi_dma_reset(xdma->v_base_addr);

    /*<! 1 = Run - Start DMA operations ,Mask interrupts*/
    axi_dma_write(xdma->v_base_addr, MM2S_CR_OFFSET, 0xf001);
    axi_dma_write(xdma->v_base_addr, S2MM_CR_OFFSET, 0xf001);
}

unsigned int copy_to_pl(xdma_handle *xdma)
{
    unsigned int status;
    /*<! set source addresses */
    axi_dma_write(xdma->v_base_addr, MM2S_SRCADDR_OFFSET, SRC_PHY_ADDR);

    /*<! set trans len*/
    axi_dma_write(xdma->v_base_addr, MM2S_BUFFLEN_OFFSET, xdma->wt_len); 

    do{
       status = axi_dma_read(xdma->v_base_addr, MM2S_SR_OFFSET);
    }while(!(status & 0x02));

    return status;
}

unsigned int copy_from_pl(xdma_handle *xdma)
{
    unsigned int status;
    /*<! set destination addresses */
    axi_dma_write(xdma->v_base_addr, S2MM_SRCADDR_OFFSET, DES_PHY_ADDR);

    /*<! set trans len*/
    axi_dma_write(xdma->v_base_addr, S2MM_BUFFLEN_OFFSET, xdma->rd_len); 

    do{
       status = axi_dma_read(xdma->v_base_addr, S2MM_SR_OFFSET);
    }while(!(status & 0x02));

    return status;
}

void source_buff_init()
{
    int *dat = (int *)xdma_hd.src, i;

    for(i=0; i<512/4; i++,dat++){
        *dat = i;
        // printf("%x\r\n", *dat); 
    }
}

int check_data()
{
    int *dat = (int *)xdma_hd.des, i;

    for(i=0; i<512/4; i++,dat++){
        if(*dat != i) return 0;
    }
    return 1;
}

void xdma_test()
{

    printf("========================\r\n");
    printf("   Start XDMA test\r\n");
    printf("========================\r\n");

    axi_dma_init();
    source_buff_init();
    copy_to_pl(&xdma_hd);
    copy_from_pl(&xdma_hd);
    if(check_data() == 1){
        printf("XDMA transfer successful\r\n");
    }
    else{
        printf("XDMA transfer faile!\r\n");
    }
}

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Qt 5.12.9 mpsoc上运行时缺少glibc_2.29的原因可能是系统中安装的glibc版本过低。glibc是GNU C Library的缩写,是Linux系统中的核心C库,提供了对操作系统底层功能的访问。 为了解决这个问题,可以考虑以下几种解决方案: 1. 升级glibc:尝试在系统中升级glibc到2.29或更高版本。可以通过更新操作系统或手动编译安装最新版本的glibc来完成。 2. 兼容库:如果升级glibc不可行或不推荐,可以尝试使用兼容库来解决问题。可以搜索并下载适用于Qt 5.12.9 mpsoc和当前系统glibc版本的兼容库,然后将其配置为Qt项目的依赖项。 3. 降级Qt版本:如果以上两种解决方案都不可行,可以考虑降级Qt版本至一个与当前系统glibc版本兼容的版本。首先需要卸载当前安装的Qt 5.12.9 mpsoc,然后安装一个较低版本的Qt,其所需的glibc版本应与当前系统中存在的版本匹配。 需要注意的是,以上解决方案中的每一种都有其特定的风险和限制。在进行任何更改之前,强烈建议备份系统和相关数据,并仔细评估可能导致的影响。此外,最好咨询相关领域的专业人士或Qt社区的支持,以获取准确和可靠的建议。 ### 回答2: 在运行Qt5.12.9 MPSOC时出现缺少"glibc_2.29"的问题。这种情况通常是由于在你的系统中缺少所需版本的GLIBC库引起的。GLIBC是一个重要的库,它提供了许多标准C库函数的实现。 要解决这个问题,可以采取以下几个步骤: 1. 检查当前系统中已安装的GLIBC版本。可以在终端中输入命令`ldd --version`来查看当前GLIBC的版本。如果显示的版本较低(低于2.29),则需要升级GLIBC。 2. 升级GLIBC。通常,升级GLIBC可能是一个相对复杂和冒险的过程,因为它涉及到操作系统的核心组件。因此,建议谨慎操作,并确保备份你的重要数据。 3. 安装兼容的Qt版本。而不是升级GLIBC,另一种解决方法是安装与你的系统兼容的Qt版本。可以查找和下载与已安装GLIBC版本兼容的Qt5.12.9版本,然后重新编译和运行你的程序。 4. 更新操作系统。将操作系统升级到支持所需GLIBC版本的最新版本可能是更简单和安全的解决方法。在系统升级之前,建议备份重要数据和设置,以防意外发生。 需要注意的是,升级GLIBC或操作系统可能会涉及到一些风险和复杂性,因此在执行此类操作之前,请确保了解相关知识或咨询专业人士的建议。 ### 回答3: 在Qt5.12.9 MPSOC上运行缺少glibc_2.29可能是因为您的操作系统中的glibc版本太旧,无法满足Qt5.12.9对于glibc_2.29的依赖。glibc(GNU C Library)是一个重要的C语言运行时库,它提供了使用C语言编写的应用程序与操作系统之间进行交互的接口。 要解决这个问题,您有以下几个选择: 1. 升级您的操作系统:升级您的操作系统到支持glibc_2.29版本的版本。您可以查找操作系统的官方文档,了解如何升级glibc版本的方法。 2. 降低Qt版本:如果您不想升级操作系统,可以尝试降低Qt的版本,以适应您当前操作系统所支持的glibc版本。您可以在Qt的官方网站上获取旧版本的Qt,然后安装并尝试在MPSOC上运行。 3. 自行编译:如果您具备一定的编程和系统知识,您也可以尝试自行编译glibc_2.29版本,并将其安装到您的操作系统中。这需要一些复杂的步骤,包括下载glibc源代码、配置编译选项、编译和安装等。 无论您选择哪种方法,确保在进行任何操作之前备份您的重要数据。另外,请注意,更改操作系统或修改底层库的操作可能会带来一些潜在的风险和不稳定性,因此请小心操作,并确保使用合适的解决方案以解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值