Advertisement
Guest User

Untitled

a guest
Apr 19th, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.63 KB | None | 0 0
  1. /**
  2.  * @file axidma_transfer.c
  3.  * @date Sunday, November 29, 2015 at 12:23:43 PM EST
  4.  * @author Brandon Perez (bmperez)
  5.  * @author Jared Choi (jaewonch)
  6.  *
  7.  * This program performs a simple AXI DMA transfer. It takes the input file,
  8.  * loads it into memory, and then sends it out over the PL fabric. It then
  9.  * receives the data back, and places it into the given output file.
  10.  *
  11.  * By default it uses the lowest numbered channels for the transmit and receive,
  12.  * unless overriden by the user. The amount of data transfered is automatically
  13.  * determined from the file size. Unless specified, the output file size is
  14.  * made to be 2 times the input size (to account for creating more data).
  15.  *
  16.  * This program also handles any additional channels that the pipeline
  17.  * on the PL fabric might depend on. It starts up DMA transfers for these
  18.  * pipeline stages, and discards their results.
  19.  *
  20.  * @bug No known bugs.
  21.  **/
  22.  
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <stdbool.h>
  26. #include <assert.h>
  27.  
  28. #include <fcntl.h>              // Flags for open()
  29. #include <sys/stat.h>           // Open() system call
  30. #include <sys/types.h>          // Types for open()
  31. #include <sys/mman.h>
  32. #include <unistd.h>             // Close() system call
  33. #include <string.h>             // Memory setting and copying
  34. #include <getopt.h>             // Option parsing
  35. #include <errno.h>              // Error codes
  36. #include <sqlite3.h>
  37.  
  38. #include "util.h"               // Miscellaneous utilities
  39. #include "conversion.h"         // Convert bytes to MBs
  40. #include "libaxidma.h"          // Interface ot the AXI DMA library
  41. /*----------------------------------------------------------------------------
  42.  * Internal Definitions
  43.  *----------------------------------------------------------------------------*/
  44.  
  45. #define READ_LENGTH 1440
  46. #define READ_WIDTH 4
  47. #define FIFO_LENGTH 32768
  48. #define MAX_NUM_CYCLES_AVG 24
  49.  
  50. // A convenient structure to carry information around about the transfer
  51. struct dma_transfer {
  52.     void *input_buf;        // The buffer to hold the input data
  53.     int output_fd;          // The file descriptor for the output file
  54.     int output_channel;     // The channel used to receive the data
  55.     int output_size;        // The amount of data to receive
  56.     uint *output_buf;       // The buffer to hold the output
  57. };
  58.  
  59. static int transfer_file(axidma_dev_t dev, struct dma_transfer *trans) {
  60.     int rc;
  61.     float resultBuf[4000];
  62.  
  63.     // Allocate a buffer for the output file
  64.     if (trans->output_buf == NULL) {
  65.         rc = -ENOMEM;
  66.     }
  67.  
  68.     // Perform the transfer
  69.     // Perform the main transaction
  70.     rc = axidma_oneway_transfer(dev, trans->output_channel, trans->output_buf,
  71.             trans->output_size, true);
  72.     if (rc < 0) {
  73.         fprintf(stderr, "DMA read transaction failed.\n");
  74.     }
  75.  
  76.     // Write the data to the output file
  77.     //printf("Writing output data to `%s`.\n", output_path);
  78.     for(int i=0; i<READ_LENGTH; i++){
  79.         resultBuf[i] = ((float)trans->output_buf[i])/71643.667;
  80.     }
  81.  
  82.     rc = robust_write(trans->output_fd, (char*) resultBuf, sizeof(float)*READ_LENGTH);
  83.  
  84.  
  85.     return rc;
  86. }
  87.  
  88.  
  89. int program_init(int* memfd, volatile int** bufferLenW, axidma_dev_t* axidma_dev, struct dma_transfer* trans){
  90.    
  91.     const array_t *rx_chans;
  92.  
  93.     //Attempt to open /dev/mem
  94.     *memfd = open("/dev/mem",O_RDWR|O_SYNC);
  95.     if(*memfd < 0) {
  96.         return -1;
  97.     }
  98.  
  99.     //Map FIFO Length Register into memory
  100.     *bufferLenW = (int*) mmap(0, 4096UL, PROT_READ | PROT_WRITE, MAP_SHARED, *memfd, 0x81200000);
  101.     printf("FIFO Length Register Mapped @ %X \n", bufferLenW);
  102.  
  103.     // Initialize the AXIDMA device
  104.     *axidma_dev = axidma_init();
  105.     if (axidma_dev == NULL) {
  106.         return -2;
  107.     }
  108.  
  109.     //Get List of Rx Channels
  110.     rx_chans = axidma_get_dma_rx(*axidma_dev);
  111.     if (rx_chans->len < 1) {
  112.         axidma_destroy(*axidma_dev);
  113.         return -ENODEV;
  114.     }
  115.  
  116.     //Select the first read channel and set the read size
  117.     trans->output_channel = rx_chans->data[0];
  118.     trans->output_size = READ_LENGTH * READ_WIDTH;
  119.     return 0;
  120. }
  121.  
  122. void program_exit(int exitCode){
  123.     switch(exitCode){
  124.         case -1:
  125.             fprintf(stderr, "Unable to open /dev/mem. You must be the root user.\n");
  126.             exit(-1);
  127.         case -2:
  128.             fprintf(stderr, "Unable to initialise the AXI DMA device.\n");
  129.             exit(-2);
  130.         case -ENODEV:
  131.             fprintf(stderr, "AXI DMA device has no read channels.\n");
  132.             exit(-ENODEV);
  133.         default:
  134.             fprintf(stderr, "Unknown error.\n");
  135.             exit(exitCode);
  136.     }
  137. }
  138.  
  139. int generate_cycle_avg(uint* cycleAvg[], long long cycleAcmResult[], float cycleAvgResult[], uint* dmaBuf, int* numCyclesAvg, uint* targetCyclesAvg){
  140.    
  141.     //printf("Check if we're removing the final buffers\n   NUM: %d\n   TGT: %u\n", *numCyclesAvg, *targetCyclesAvg);
  142.  
  143.     //printf("Pointer array:\n");
  144.  
  145.     //for(int i = 0; i < MAX_NUM_CYCLES_AVG; i++) {
  146.     //    printf("[%X]", cycleAvg[i]);
  147.     //}
  148.  
  149.     //printf("\n");
  150.  
  151.     if (*targetCyclesAvg < *numCyclesAvg) {
  152.         //printf("Remove 2 buffers\n");
  153.         //Remove the final two buffers from the accumulated result
  154.         for(int i = (*numCyclesAvg - 2); i < *numCyclesAvg; i++){
  155.             for(int j = 0; j < READ_LENGTH; j++) {
  156.                 cycleAcmResult[j] -= cycleAvg[i][j];
  157.             }
  158.  
  159.         }
  160.  
  161.         //Free the final two buffers that were just cleared from the accumulated result
  162.         //printf("Final addresses:\n%X\n%X\n", cycleAvg[*numCyclesAvg -1], cycleAvg[*numCyclesAvg - 2]);
  163.         free(cycleAvg[*numCyclesAvg-1]);
  164.         free(cycleAvg[*numCyclesAvg-2]);
  165.  
  166.  
  167.         //Update the buffer count
  168.         *numCyclesAvg = *numCyclesAvg - 2;
  169.  
  170.     } else if (*targetCyclesAvg == *numCyclesAvg) {
  171.         //printf("Remove 1 buffer\n");
  172.         //Subtract the final buffer from the accumulated result
  173.         for(int j = 0; j < READ_LENGTH; j++) {
  174.                 cycleAcmResult[j] -= cycleAvg[*numCyclesAvg-1][j];
  175.         }
  176.  
  177.         //printf("Attempt to free the final pointer\n");
  178.         //Free the final pointer
  179.         free(cycleAvg[(*numCyclesAvg-1)]);
  180.         //Update the buffer count
  181.         *numCyclesAvg = *numCyclesAvg - 1;
  182.     }
  183.    
  184.     //printf("Shift all buffers up\n");
  185.     //Shift all buffers up a place
  186.  
  187.     for(int i = *numCyclesAvg-1; i >= 0; i--){
  188.         //printf("i = %d,  Shift\n", i);
  189.         cycleAvg[i+1] = cycleAvg[i];
  190.     }
  191.  
  192.     //printf("Add a new buffer\n");
  193.     //Add a new buffer
  194.     cycleAvg[0] = (uint*) malloc(READ_LENGTH*sizeof(uint));
  195.  
  196.  
  197.     //printf("Populate the new buffer\n", *numCyclesAvg);
  198.     //Populate the new buffer and add to the accumulated result
  199.     for(int i=0; i < READ_LENGTH; i++){
  200.         cycleAvg[0][i] = dmaBuf[i];
  201.         cycleAcmResult[i] += (uint) dmaBuf[i];
  202.     }
  203.  
  204.     //Update the buffer count
  205.     *numCyclesAvg = *numCyclesAvg + 1;
  206.  
  207.     //printf("Generate the average result\n\n\n");
  208.     //Generate the cycle average result
  209.     for(int i = 0; i < READ_LENGTH; i++) {
  210.         cycleAvgResult[i] = ((float)cycleAcmResult[i])/(*numCyclesAvg)/71643.667;
  211.     }
  212. }
  213.  
  214.  
  215. static int select_callback(int *data, int argc, char** argv, char** err) {
  216.     *data = atoi(argv[0]);
  217. }
  218.  
  219. int main(int argc, char **argv)
  220. {
  221.     //Variable Declarations
  222.     int memfd = 0;
  223.     int returnVal = 0;
  224.     char outFileName[50];
  225.     char avgFileName[50];
  226.     char rmFileName[50];
  227.     char rmAvgFileName[50];
  228.  
  229.     sqlite3 *db;
  230.     uint *cycleAvg[MAX_NUM_CYCLES_AVG];
  231.     float* cycleAvgResult;
  232.     long long* cycleAcmResult;
  233.     int cycleAvgFd = 0;
  234.     uint initCycleCount = 0; //Used to initially fill the accumulation array
  235.     int numCyclesAvg = 0;
  236.     uint targetCyclesAvg = 12;
  237.     char* sqlErr;
  238.  
  239.     //Zero all the pointers in the cycleAvg array
  240.     for (int i = 0; i < MAX_NUM_CYCLES_AVG; i++){
  241.         cycleAvg[i] = 0;
  242.     }
  243.  
  244.     cycleAvgResult = (float*) malloc(READ_LENGTH*sizeof(float));
  245.     cycleAcmResult = (long long*) malloc(READ_LENGTH*sizeof(long long));
  246.     for(int i = 0; i < READ_LENGTH; i++){
  247.         cycleAvgResult[i] = 0;
  248.         cycleAcmResult[i] = 0;
  249.     }
  250.  
  251.     volatile int *bufferLenW;
  252.     axidma_dev_t axidma_dev;
  253.     struct dma_transfer trans;
  254.  
  255.     //Begin Main
  256.     returnVal = program_init(&memfd, &bufferLenW, &axidma_dev, &trans);
  257.     printf("Returned %d from program init()\n", returnVal);
  258.     if(returnVal < 0){
  259.         program_exit(returnVal);
  260.     }
  261.    
  262.     //Open the SQL database (this should be moved to the init function later)
  263.     returnVal = sqlite3_open("/mnt/ramdisk/settings.db", &db);
  264.  
  265.     if(returnVal){
  266.         fprintf(stderr, "Failed to open the database\n");
  267.         exit(returnVal);
  268.     }
  269.  
  270.     //Inital output
  271.     printf("AXI DMA File Transfer Info:\n");
  272.     printf("\tReceive Channel: %d\n", trans.output_channel);
  273.     printf("\tFIFO buffer length: %u\n", bufferLenW);
  274.  
  275.     //allocate a transfer buffer
  276.     trans.output_buf = axidma_malloc(axidma_dev, trans.output_size);
  277.  
  278.  
  279.     /*** MAIN TRANSFER LOOP ***/
  280.     int i = 0;
  281.     while(1){
  282.         if(i == 999){
  283.             i = 0;
  284.             //remove old files
  285.             for(int j = 987; j < 999; j++){
  286.                 sprintf(rmFileName, "/mnt/ramdisk/cycle%03d", j);
  287.                 sprintf(rmAvgFileName, "/mnt/ramdisk/avg%03d", j);
  288.                 remove(rmFileName);
  289.                 remove(rmAvgFileName);
  290.             }
  291.         }
  292.         //Set the file names
  293.         sprintf(outFileName, "/mnt/ramdisk/cycle%03d", i);
  294.         sprintf(avgFileName, "/mnt/ramdisk/avg%03d", i);
  295.         sprintf(rmFileName, "/mnt/ramdisk/cycle%03d", i-12);
  296.         sprintf(rmAvgFileName, "/mnt/ramdisk/avg%03d", i-12);
  297.         i++;
  298.         //Attempt to open a new file
  299.         trans.output_fd = open(outFileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH);
  300.         cycleAvgFd = open(avgFileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH);
  301.         if (trans.output_fd < 0) {
  302.             fprintf(stderr, "Unable to create output file: %s\n", outFileName);
  303.             axidma_free(axidma_dev, trans.output_buf, trans.output_size);
  304.             continue;
  305.         }
  306.  
  307.         //Attempt to remove an old file
  308.         if(i > 11){
  309.             remove(rmFileName);
  310.             remove(rmAvgFileName);
  311.         }
  312.  
  313.         int writeBuffer0 = 0;
  314.         int writeBuffer1 = 0;
  315.  
  316.         //check for buffer overrun
  317.         if((*bufferLenW > FIFO_LENGTH) && i > 0){
  318.             printf("FIFO buffer overrun\n");
  319.         }
  320.  
  321.         //wait until there are enough bytes to perform a read
  322.         int sleepTime = 0;
  323.         while(*bufferLenW < READ_LENGTH){
  324.             usleep(100);
  325.             sleepTime += 100;
  326.             if(sleepTime > 1000000){
  327.                 printf("Sleep: %d\n", *bufferLenW);
  328.                 sleepTime = 0;
  329.             }
  330.         }
  331.  
  332.         //Perform the DMA transfer
  333.         writeBuffer0 = *bufferLenW;
  334.         transfer_file(axidma_dev, &trans);
  335.         writeBuffer1 = *bufferLenW;
  336.         close(trans.output_fd);
  337.         printf("%u before transaction, %u after transaction   -   Slider:%u\n", writeBuffer0, writeBuffer1, targetCyclesAvg);
  338.  
  339.         //Generate the new cycle average
  340.         generate_cycle_avg(cycleAvg, cycleAcmResult, cycleAvgResult, trans.output_buf, &numCyclesAvg, &targetCyclesAvg);
  341.         robust_write(cycleAvgFd, (char*) cycleAvgResult, sizeof(float)*READ_LENGTH);
  342.         close(cycleAvgFd);
  343.  
  344.         //Update the cycleAverageTarget from the database
  345.         returnVal = sqlite3_exec(db, "SELECT val FROM settings WHERE id='numSampleAvg'", select_callback, &targetCyclesAvg, &sqlErr);
  346.     }
  347.  
  348.     return 0;
  349. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement