DMA在linux下PS端c语言相关内容

2019-04-15 15:56发布

背景: 片上单片机与PC通过UART相连并且可以通过PC对片上单片机进行相应的指令操作。 片上单片机可以运行相应编译好的c程序,控制相应的IPcore从而用FPGA上的IPcore进行相应的运算。 相关c源码通过编译可以变为可执行文件拷入u盘,然后片上单片机可以通过挂载u盘执行可执行文件。 目的: 读懂程序。程序的目的为:单片机运行简单的卷积操作,单片机控制的IPcore也运行卷积操作,然后两个卷积操作结果数据之间进行对比。结果相同则表示运行无误,输出相应的结果。 目录 生成卷积IPcore时c语言相关内容 1.关于主函数的参数 2.关于文件的操作 3.memcmp函数 4.atoi函数 5.memset 6.函数与IPcore通信的核心语句 6.1 打开DMA通信 6.2 单片机向IPcore写数据 6.3 单片机从IPcore读数据
与之对应的IPcore内容:生成卷积IPcore时c语言相关内容 PS端代码: #include #include #include #include #include unsigned long tStart, tEnd; unsigned long data; float buf_in[27*600] = {}; float buf_out[float buf_out[16*600] = {}; float weights[16*27] = {}; unsigned long getTime(){ struct timeval temp; gettimeofday(&temp, NULL); return temp.tv_sec * 1000 * 1000 + temp.tv_usec; } void report(char *msg, unsigned long data, unsigned long time, unsigned long dmaUsed){ printf("%s %ld %ld %f %d ", msg, data, time, data * 1.0 / time, dmaUsed); FILE *f = fopen("report.dat", "a"); fprintf(f, "%s %ld %ld %f %d ", msg, data, time, data * 1.0 / time, dmaUsed); fclose(f); } #define REPORT(f, timeStart, timeEnd, dataPtr, msg, dmaUsed) *timeStart = getTime(); *dataPtr = f; *timeEnd = getTime(); report(msg, *dataPtr, *timeEnd - *timeStart, dmaUsed); void checkData(float *bufferIn, float *bufferOut, unsigned int elems){ int i; for (i = 0; i < elems; i++) { if (bufferIn[i] != bufferOut[i]) printf("[%d] %f->%f ", i, bufferIn[i], bufferOut[i]); } } unsigned long memCpy_ARM(char *bufferIn, char *bufferOut, unsigned long elems, size_t size){ int i; for(i=0; i FIFO_LEN ? FIFO_LEN : size * elems - byteMoved; ret = write(fd, &bufferIn[byteMoved], byteToMove); if (ret != byteToMove) printf("write DMA error %d! ", ret); else printf("write DMA %d ", ret); byteMoved += byteToMove; } printf("Write Total %d ", byteMoved); byteMoved = 0; while(byteMoved!=READ_LEN){ byteToMove = READ_LEN - byteMoved > FIFO_LEN ? FIFO_LEN : READ_LEN - byteMoved; ret = read(fd, &bufferOut[byteMoved], byteToMove); if (ret != byteToMove) printf("read DMA error %d ", ret); else printf("read DMA %d ", ret); byteMoved += byteToMove; } printf("Read Total %d ", byteMoved); close(fd); return elems * size * dmaToUse; } void cnn_simulate(float *in, float *out) { float *bufferIn, *bufferOut; int i, j, k; float result, temp; bufferIn = (float *) malloc(4*27*600); bufferOut = (float *) malloc(4*16*600); for (i = 0; i < 27*600; i++) bufferIn[i] = in[i]; for (i = 0; i < 16; i++) { for (j = 0; j < 600; j++) { result = 0; for (k = 0; k < 27; k++) { temp = weights[i*27+k] * bufferIn[k*600+j]; result += temp; } bufferOut[i*600+j] = result; } } for (i = 0; i < 16*600; i++) out[i] = bufferOut[i]; } int main(int argc, char **argv) { float *bufferIn, *bufferOut_ARM, *bufferOut_DMA; float *weightsIn; int fd, ret; int size_float = sizeof(float); if(argc!=3){ printf("Usage: ./dmaBench DATA_IN DATA_OUT "); exit(0); } unsigned long size_in = atoi(argv[1]); unsigned long size_out = atoi(argv[2]); printf("in %d, out %d ", size_in, size_out); bufferIn = (float *) malloc(size_float * size_in); bufferOut_DMA = (float *) malloc(size_float * size_out); bufferOut_ARM = (float *) malloc(size_float * size_out); int i; for (i = 0; i < size_in; i++) bufferIn[i] = buf_in[i]; cnn_simulate(bufferIn, bufferOut_ARM); fd = open("/dev/axi-dma1", O_RDWR); if (fd < 0) { printf("open axi-dma1 failed! "); return -1; } //ret = write(fd, (unsigned char *)weightsIn, size_float*27*16); //if (ret != size_float*27*16) // printf("import weights failed! "); ret = write(fd, (unsigned char *)bufferIn, size_float * size_in); if (ret != size_float * size_in) printf("import image data failed %d ", ret); ret = read(fd, (unsigned char *)bufferOut_DMA, size_float * size_out); if (ret != size_float * size_out) printf("read error %d ", ret); for (i = 0; i < size_out; i++) { if (bufferOut_ARM[i] != bufferOut_DMA[i]) printf("[%d] %f - > %f ", i, bufferOut_ARM[i], bufferOut_DMA[i]); } free(bufferIn); free(bufferOut_DMA); free(bufferOut_ARM); return 0; }  

1.关于主函数的参数

  int main(int argc, char* argv[]) argc是argument count的简称,argv是argument variable的简称,也就是,argc指代参数的个数,argv指代每个参数
  • argv[0] 指向程序运行的全路径名
  • argv[1] 指向在DOS命令行中执行程序名后的第一个字符串
  • argv[2] 指向执行程序名后的第二个字符串
  • argv[argc]为NULL。
例如:输入"test c:/testPic/01.jpg",就是在启动test.exe程序的同时,给该程序指定一个额外的参数“c:/testPic/01.jpg”。这里,argc也就是参数的个数,就是2个,test为第一个参数,空格之后的“c:/testPic/01.jpg”是第二个参数,换句话说,argc=2, argv[0]="test",argv[1]="c:/testPic/01.jpg"。 针对本程序,我们的输入就是   inSize  outSize

2.关于文件的操作

getc 从文件中读取字符 getc(fp),fp为文件指针 gets 从缓冲区中读取字符串 fopen与open的区别,`fopen`是C标准函数,因此拥有良好的移植性;而`open`是UNIX系统调用,移植性有限。open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。 所以fd = open("/dev/axi-dma1", O_RDWR); 就是以打开方式进行相应的AXI总线与DMA操作。 wirte 函数  ssize_t write(int fd, const void *buf, size_t nbyte); fd:文件描述符; buf:指定的缓冲区,即指针,指向一段内存单元; nbyte:要写入文件指定的字节数; 返回值:写入文档的字节数(成功);-1(出错) write函数把buf中nbyte写入文件描述符handle所指的文档,成功时返回写的字节数,错误时返回-1. read函数  ssize_t read(int fd, void *buf, size_t count); read()会把参数fd所指的文件传送nbyte个字节到buf指针所指的内存中。若参数nbyte为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或无可读取的数据。错误返回-1,

3.memcmp函数

memcmp是比较内存区域buf1和buf2的前count个字节。该函数是按字节比较的。 当buf1buf2时,返回值大于0

4.atoi函数

  C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。 unsigned long size_in = atoi(argv[1]); unsigned long size_out = atoi(argv[2]);   根据主函数中此段程序,我们知道了输入的第一个参数为函数名,第二个参数为输入的size,第三个参数为输出的size。

5.memset

void *memset(void *s, int ch, size_t n); 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。 memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体数组进行清零操作的一种最快方法

6.函数与IPcore通信的核心语句

6.1 打开DMA通信

fd = open("/dev/axi-dma1", O_RDWR); if (fd < 0) { printf("Open axi-dma1 failed! "); return -1; } 打开与DMA之间的通信,也就是单片机与IPcore之间的通信。

6.2 单片机向IPcore写数据

ret = write(fd, (unsigned char *)bufferIn, size_float * size_in); if (ret != size_float * size_in) printf("write image data from bufferIn to DMA failed %d ", ret); 单片机向IPcore写数据,把bufferIn中的数据通过之前open的fd写入size_float * size_in个字节的数据。若写入不成功返回-1,写入成功,返回写入的字节数。

6.3 单片机从IPcore读数据

ret = read(fd, (unsigned char *)bufferOut_DMA, size_float * size_out); if (ret != size_float * size_out) printf("read from DMA to bufferOut_DMA failed %d ", ret); 单片机从IPcore读数据,IPcore中传出的数据通过之前open的fd读入size_float * size_out个字节的数据,存入bufferOut_DMA。若读入不成功返回-1,若读成功,返回读入的字节数。   所以程序就是运用open来打开dma的通信,然后用read和write来进行单片机对IP core的读和写。