接上一篇博客《PS与PL通信(AXI DMA)》https://blog.csdn.net/hongmao6/article/details/110626857

源码从git上获取,xilinx_axidma-master;

源码里面包含了驱动代码、应用层的代码、库文件;

源码:

1、将源码拷贝到内核源码中,如下图所示:

2、cd xilinx-axidma-master

3、执行命令:

make CROSS_COMPILE=arm-xilinx-linux-gnueabi- ARCH=arm KBUILD_DIR=/home/STG/linux-adi-4.9.0 clean && make CROSS_COMPILE=arm-xilinx-linux-gnueabi- ARCH=arm KBUILD_DIR=/home/STG/linux-adi-4.9.

4、编译完成后,会生成outputs目录,在outputs目录下是编译好的模块ko与应用程序、库文件。

5、axidma_test源码,根据axidma_transfer修改,添加了UDP发送数据到PC。

/**
 * @file axidma_transfer.c
 * @date Sunday, November 29, 2015 at 12:23:43 PM EST
 * @author Brandon Perez (bmperez)
 * @author Jared Choi (jaewonch)
 *
 * This program performs a simple AXI DMA transfer. It takes the input file,
 * loads it into memory, and then sends it out over the PL fabric. It then
 * receives the data back, and places it into the given output file.
 *
 * By default it uses the lowest numbered channels for the transmit and receive,
 * unless overriden by the user. The amount of data transfered is automatically
 * determined from the file size. Unless specified, the output file size is
 * made to be 2 times the input size (to account for creating more data).
 *
 * This program also handles any additional channels that the pipeline
 * on the PL fabric might depend on. It starts up DMA transfers for these
 * pipeline stages, and discards their results.
 *
 * @bug No known bugs.
 **/

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#include <fcntl.h>              // Flags for open()
#include <sys/stat.h>           // Open() system call
#include <sys/types.h>          // Types for open()
#include <unistd.h>             // Close() system call
#include <string.h>             // Memory setting and copying
#include <getopt.h>             // Option parsing
#include <errno.h>              // Error codes

#include "util.h"               // Miscellaneous utilities
#include "conversion.h"         // Convert bytes to MiBs
#include "libaxidma.h"          // Interface ot the AXI DMA library

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#define SERVER_PORT 8080
#define BUFF_LEN 512
#define SERVER_IP "192.168.11.124"

typedef enum test_type{    
	READ_WRITE_TEST = 0,    
	READ_TEST,    
	WRITE_TEST
}testtype;

#define READ_SIZE	0x400	//1KB -1

testtype axidma_testtype = READ_WRITE_TEST;

int client_fd;
struct sockaddr_in ser_addr;

// Converts a tval struct to a double value of the time in seconds
#define TVAL_TO_SEC(tval) \
    (((double)(tval).tv_sec) + (((double)(tval).tv_usec) / 1000000.0))

// Converts a byte (integral) value to megabytes (floating-point)
#define BYTE_TO_MB(size) (((double)(size)) / (1024.0 * 1024.0))

// Converts a megabyte (floating-point) value to bytes (integral)
#define MB_TO_BYTE(size) ((size_t)((size) * 1024.0 * 1024.0))


/*----------------------------------------------------------------------------
 * Internal Definitions
 *----------------------------------------------------------------------------*/

// A convenient structure to carry information around about the transfer
struct dma_transfer {
    int input_fd;           // The file descriptor for the input file
    int input_channel;      // The channel used to send the data
    int input_size;         // The amount of data to send
    void *input_buf;        // The buffer to hold the input data
    int output_fd;          // The file descriptor for the output file
    int output_channel;     // The channel used to receive the data
    int output_size;        // The amount of data to receive
    void *output_buf;       // The buffer to hold the output
};


int init_udp()
{


    client_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(client_fd < 0)
    {
        printf("create socket fail!\n");
        return -1;
    }

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
   // ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //注意网络序转换
    ser_addr.sin_port = htons(SERVER_PORT);  //注意网络序转换


    return 0;
}


/*----------------------------------------------------------------------------
 * Command Line Interface
 *----------------------------------------------------------------------------*/

// Prints the usage for this program
static void print_usage(bool help)
{
    FILE* stream = (help) ? stdout : stderr;

    fprintf(stream, "Usage: axidma_transfer <input path> <output path> "
            "[-t <DMA tx channel>] [-r <DMA rx channel>] [-s <Output file size>"
            " | -o <Output file size>].\n");
    if (!help) {
        return;
    }

    fprintf(stream, "\t<input path>:\t\tThe path to file to send out over AXI "
            "DMA to the PL fabric. Can be a relative or absolute path.\n");
    fprintf(stream, "\t<output path>:\t\tThe path to place the received data "
            "from the PL fabric into. Can be a relative or absolute path.\n");
    fprintf(stream, "\t-t <DMA tx channel>:\tThe device id of the DMA channel "
            "to use for transmitting the file. Default is to use the lowest "
            "numbered channel available.\n");
    fprintf(stream, "\t-r <DMA rx channel>:\tThe device id of the DMA channel "
            "to use for receiving the data from the PL fabric. Default is to "
            "use the lowest numbered channel available.\n");
    fprintf(stream, "\t-s <Output file size>:\tThe size of the output file in "
            "bytes. This is an integer value that must be at least the number "
            "of bytes received back. By default, this is the same as the size "
            "of the input file.\n");
    fprintf(stream, "\t-o <Output file size>:\tThe size of the output file in "
            "Mibs. This is a floating-point value that must be at least the "
            "number of bytes received back. By default, this is the same "
            "the size of the input file.\n");
    return;
}

/* Parses the command line arguments overriding the default transfer sizes,
 * and number of transfer to use for the benchmark if specified. */
static int parse_args(int argc, char **argv, char **input_path,
    char **output_path, int *input_channel, int *output_channel, int *output_size)
{
    char option;
    int int_arg;
    double double_arg;
    bool o_specified, s_specified;
    int rc;

    // Set the default values for the arguments
    *input_channel = -1;
    *output_channel = -1;
    *output_size = -1;
    o_specified = false;
    s_specified = false;
    rc = 0;

    while ((option = getopt(argc, argv, "t:r:s:o:h:wd")) != (char)-1)
    {
        switch (option)
        {
            // Parse the transmit channel device id
            case 't':
                rc = parse_int(option, optarg, &int_arg);
                if (rc < 0) {
                    print_usage(false);
                    return rc;
                }
                *input_channel = int_arg;
                break;

            // Parse the receive channel device id
            case 'r':
                rc = parse_int(option, optarg, &int_arg);
                if (rc < 0) {
                    print_usage(false);
                    return rc;
                }
                *output_channel = int_arg;
                break;

            // Parse the output file size (in bytes)
            case 's':
		printf("%s--%d\n",__FUNCTION__,__LINE__);
                rc = parse_int(option, optarg, &int_arg);
                if (rc < 0) {
                    print_usage(false);
                    return rc;
                }
                *output_size = int_arg;
                s_specified = true;
                break;

            // Parse the output file size (in MiBs)
            case 'o':
                rc = parse_double(option, optarg, &double_arg);
                if (rc < 0) {
                    print_usage(false);
                    return rc;
                }
                *output_size = MIB_TO_BYTE(double_arg);
                o_specified = true;
                break;
	    case 'w':
                axidma_testtype = WRITE_TEST;
                break;
            case 'd':
		axidma_testtype = READ_TEST;
		 break;
            case 'h':
                print_usage(true);
                exit(0);

            default:
                print_usage(false);
                return -EINVAL;
        }
    }

    // If one of -t or -r is specified, then both must be
    if ((*input_channel == -1) ^ (*output_channel == -1)) {
        fprintf(stderr, "Error: Either both -t and -r must be specified, or "
                "neither.\n");
        print_usage(false);
        return -EINVAL;
    }

    // Only one of -s and -o can be specified
    if (s_specified && o_specified) {
        fprintf(stderr, "Error: Only one of -s and -o can be specified.\n");
        print_usage(false);
        return -EINVAL;
    }

    // Check that there are enough command line arguments
    if (optind > argc-2) {
        fprintf(stderr, "Error: Too few command line arguments.\n");
        print_usage(false);
        return -EINVAL;
    }

    // Check if there are too many command line arguments remaining
    if (optind < argc-2) {
        fprintf(stderr, "Error: Too many command line arguments.\n");
        print_usage(false);
        return -EINVAL;
    }

    // Parse out the input and output paths
    *input_path = argv[optind];
    *output_path = argv[optind+1];
    return 0;
}

/*----------------------------------------------------------------------------
 * DMA File Transfer Functions
 *----------------------------------------------------------------------------*/

static int transfer_file(axidma_dev_t dev, struct dma_transfer *trans,
                         char *output_path)
{
    int rc;
    struct timeval start_time, end_time;
    //double elapsed_time, total_data_rate;
    
    // Allocate a buffer for the input file, and read it into the buffer
    trans->input_buf = axidma_malloc(dev, trans->input_size);
    if (trans->input_buf == NULL) {
        fprintf(stderr, "Failed to allocate the input buffer.\n");
        rc = -ENOMEM;
        goto ret;
    }
    
    rc = robust_read(trans->input_fd, trans->input_buf, trans->input_size);
    if (rc < 0) {
        perror("Unable to read in input buffer.\n");
        axidma_free(dev, trans->input_buf, trans->input_size);
        return rc;
    }
    /*----------------------------------------------------------*/
    // Allocate a buffer for the output file
   if (WRITE_TEST != axidma_testtype){
		
            trans->output_buf = axidma_malloc(dev, trans->output_size);
            if (trans->output_buf == NULL) {
                rc = -ENOMEM;
		printf("%s--%d\n",__FUNCTION__,__LINE__);
                goto free_input_buf;
            }
    }
   
    /*----------------------------------------------------------*/
    if (READ_WRITE_TEST == axidma_testtype){
            printf("\n<<<<<AXI DMA Write Read Test!>>>>>\n\n");
            
            // Start Perform the transfer
            gettimeofday(&start_time, NULL);
            axidma_twoway_transfer(dev, trans->input_channel, trans->input_buf,
	            trans->input_size, NULL, trans->output_channel, trans->output_buf,
	            trans->output_size, NULL, true);
            if (rc < 0) {
                fprintf(stderr, "DMA read write transaction failed.\n");
                goto free_output_buf;
            }
            gettimeofday(&end_time, NULL);
            
            // Write the data to the output file
            printf("\nWriting output data to file:`%s`.\n", output_path);
            rc = robust_write(trans->output_fd, trans->output_buf, trans->output_size);
     }else if(WRITE_TEST == axidma_testtype){        
            printf("\n<<<<<AXI DMA Write Test!Channel:%d>>>>>\n\n",trans->input_channel);
            
            gettimeofday(&start_time, NULL);
            rc= axidma_oneway_transfer(dev,trans->input_channel,trans->input_buf, trans->input_size,true);
            if (rc < 0) {
                fprintf(stderr, "DMA write transaction failed.\n");
                goto free_input_buf;
            }
            gettimeofday(&end_time, NULL);
     }else if(READ_TEST == axidma_testtype){        
            printf("\n AXI DMA Read Test Use Channel:%d \n",trans->output_channel);
            
            gettimeofday(&start_time, NULL);
            rc= axidma_oneway_transfer(dev,trans->output_channel,trans->output_buf, trans->output_size,true);
            if (rc < 0) {
                fprintf(stderr, "DMA read  transaction failed.\n");
                goto free_output_buf;
            }
            gettimeofday(&end_time, NULL);
            
            // Write the data to the output file
            printf("\n Writing output data to file:`./%s`. And Use UDP send to PC\n", output_path);
            rc = robust_write(trans->output_fd, trans->output_buf, trans->output_size);
	    
	    //use UDP send read data to PC
	    sendto(client_fd, trans->output_buf, trans->output_size, 0, (struct sockaddr*)&ser_addr, sizeof(ser_addr));

     }else{
            printf("\n<<<<<AXI DMA Nothing Test!>>>>>\n\n");
     }
     
    /*----------------------------------------------------------*/
  
    return rc;
    /*----------------------------------------------------------*/
free_output_buf:
    axidma_free(dev, trans->output_buf, trans->output_size);
free_input_buf:
    axidma_free(dev, trans->input_buf, trans->input_size);
ret:
    return rc;
}

/*----------------------------------------------------------------------------
 * Main
 *----------------------------------------------------------------------------*/

int main(int argc, char **argv)
{
    int rc;
    char *input_path, *output_path;
    axidma_dev_t axidma_dev;
    struct stat input_stat;
    struct dma_transfer trans;
    const array_t *tx_chans, *rx_chans;

    // Parse the input arguments
    memset(&trans, 0, sizeof(trans));
    if (parse_args(argc, argv, &input_path, &output_path, &trans.input_channel,
                   &trans.output_channel, &trans.output_size) < 0) {
        rc = 1;
        goto ret;
    }

    // Try opening the input and output images
    trans.input_fd = open(input_path, O_RDONLY);
    if (trans.input_fd < 0) {
        perror("Error opening input file");
        rc = 1;
        goto ret;
    }
    trans.output_fd = open(output_path, O_WRONLY|O_CREAT|O_TRUNC,
                     S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH);
    if (trans.output_fd < 0) {
        perror("Error opening output file");
        rc = -1;
        goto close_input;
    }

    // Initialize the AXIDMA device
    axidma_dev = axidma_init();
    if (axidma_dev == NULL) {
        fprintf(stderr, "Error: Failed to initialize the AXI DMA device.\n");
        rc = 1;
        goto close_output;
    }

    // Get the size of the input file
    if (fstat(trans.input_fd, &input_stat) < 0) {
        perror("Unable to get file statistics");
        rc = 1;
        goto destroy_axidma;
    }

    // If the output size was not specified by the user, set it to the default
   // trans.input_size = input_stat.st_size;
 	
    trans.input_size = input_stat.st_size;
    if (trans.output_size == -1) {
        //trans.output_size = trans.input_size;
	trans.output_size = READ_SIZE;
    }
   

    // Get the tx and rx channels if they're not already specified
    tx_chans = axidma_get_dma_tx(axidma_dev);
    if (tx_chans->len < 1) {
        fprintf(stderr, "Error: No transmit channels were found.\n");
        rc = -ENODEV;
        goto destroy_axidma;
    }
    rx_chans = axidma_get_dma_rx(axidma_dev);
    if (rx_chans->len < 1) {
        fprintf(stderr, "Error: No receive channels were found.\n");
        rc = -ENODEV;
        goto destroy_axidma;
    }

    /* If the user didn't specify the channels, we assume that the transmit and
     * receive channels are the lowest numbered ones. */
    if (trans.input_channel == -1 && trans.output_channel == -1) {
        trans.input_channel = tx_chans->data[0];
        trans.output_channel = rx_chans->data[0];
    }
 
    //init udp 
    init_udp();
	
    // Transfer the file over the AXI DMA
    rc = transfer_file(axidma_dev, &trans, output_path);
    rc = (rc < 0) ? -rc : 0;
	

    close(client_fd);

destroy_axidma:
    axidma_destroy(axidma_dev);
close_output:
    assert(close(trans.output_fd) == 0);
close_input:
    assert(close(trans.input_fd) == 0);
ret:
    return rc;
}

 

Logo

更多推荐