上周许老师说,内容我看不太懂,但是你要认真写,不然别人看不明白还不如不写。看了下,前面的确实很笼统,接下来按照许老师说的,认真写。 进入正题,流式传输和基于地址的传输有什么区别? 直观的看,基于地址的数据传输就像是CPU访问内存,每次访问数据都需要一个地址。基于流的数据传输方式类似于FIFO,队列的访问,每次读取会把数据“读走”,下次再读取的时候已经是下一个数据,写入也是类似。再FPGA中,流式数据传输是以时钟为驱动,加一些控制信号。stream常见的实例就是AD/DA转换,AD/DA转换器在采样时钟的驱动下,不停的产生数据流,外界根据一个ready信号来决定是否读取数据。address形式常见的例子例如MCU读取AT24C04,每次发生数据的读写都会提前设置地址。 可以看出来,基于stream的数据传输更适合批量数据的传输,基于Address的数据传输适合位置型的数据。
对上面的时序图进行点说明,在AXI-STREAM总线中,有两个握手信号很关键,明白了握手信号,根据这两个信号就可以进行数据的传输。 在说信号之前,先说一下AXI-stream是分为主设备和从设备的,主设备会发出clk信号和data,从设备在条件允许的情况下,进行数据的读取。 1、tvalid信号:此信号说明主机的数据已经准备好了,数据允许被从机读取。 2、tready信号:此信号是从机目前可以读取的信号,当该信号置位时说明从机准备好了读取主机的信号; 上图是我做的测试信号, 可以看出tready&tvalid1的时刻,数据开始被传输 。 这种握手机制,相互确定了对方是否准备好进行数据传输,一旦双方都确认,数据传输就会开始,这好像TCP传输的握手机制,客户端发送给主机消息,这时候服务器知道了客户端具有发送的能力,同时服务器知道了自己有接受的能力。但是客户端不知道自己是否有发送的能力(没有收到反馈),同时客户端不知道自己是否有接收的能力(没有接收过数据)。这时服务器就会给客户端发送数据,这时候,客户端如果接收到数据,那么客户端就明确了自己有数据接收的能力(收到了数据)。同时客户端也知道了服务器有发送的能力。但是现在服务器不知道客户端知道自己具有发送的能力,于是客户端再次给服务器发送数据。这样双发都知道了自己,并且知道了对方具有数据发送和接收端的能力。 举个形象的例子,虽然跑题了,有两个隔着墙扔东西的孩子,目的是能扔到对方的手里,并且双方都知道已经扔到对方的手里,不能讲话,但是可以在被扔的东西里携带信息。 第一次,左边的扔出去,右边的小朋友成功的接上了。此时的状态是:右边的小朋友知道左边的小朋友成功了,但是左边的小朋友不知道他自己是不是已经成功了。 第二次,右边的小朋友把东西扔到左边,并且左边的小朋友收到了。这时候的状态是:左边的小朋友知道了右边的小朋友成功了,并且扔过来的纸条了说明了,你上次扔过来的纸条我收到了。但是右边的小朋友还不知道自己成功了。 第三次,左边的小朋友又给把纸条扔回去,并且在纸条了告诉右边的小朋友自己刚才收到了你上次扔过来的纸条。这样,通过三次的交互,以及其中两次携带确认信息,就能够使通信双方都明确了自己和对方都具有通信的能了,这样就能够建立TCP链接了。 跑题是为了拓宽下思路,继续回来看AXI-stream 剩下的几个信号: 3、tlast:这个信号是主机发出来的,携带在主机发出信号的最后一位。这个信号很有用,是从机得知主机完成数据传输的标志,例如用来出发DMA传输完成中断。 4、tkeep:这个信号也很关键,表示传输的数据中有哪几个 bit 是有效的。 总结一下: 1、从机拉高tready信号,表示此刻从机空闲,可以进行数据传输; 2、主机把tdata、tkeep、tuser准备就绪以后,再把tvalid拉高,此时数据在clk的驱动下进行传输; 3、TKEEP是字节修饰符。用来表明TDATA相关字节的内容是否作为数据流的一部分被处理。TKEEP字节修饰符未被确认的那些相关字节是空字节,可以从数据流中去除。 4、tlast 数据包结束;
AIX-fifo使用的是流传输的形式,因此想要与CUP进行数据交互需要用到DMA控制器。xlinxi提供的DMA IP核实现了与AXI-stream FIFO的无缝连接链接。 上图是利用vivado设计的,这里用了两个DMA控制器,虽然xilinx提供的DMA IP 核可以实现双向的数据传输,但是不能同时进行,因此使用了两个,这可以实现“全双工”。 上图红色箭头指出的是ACP类型的AXI总线,用AXI-hp也可,但是ACP可以不用担心cache一致性的问题。(cache一致性就是在CPU上的高速缓冲可能和RAM中的数据不一致,造成访问数据错误的问题)。
PL的逻辑代码很简单,等待一个VIO信号,然后拉高tready。这样是为了可控的进行数据的观察。完成PL逻辑设置,要记下来DMA控制器的地址: 然后通过C代码实现DMA控制器的访问与控制。 下面是PS的代码:
XAxiDma_Config *config; //config point XAxiDma InstancePtr; //DMA control instance int err = 0; config = XAxiDma_LookupConfig(XPAR_AXI_DMA_0_DEVICE_ID); //find config err = XAxiDma_CfgInitialize(&InstancePtr, config); /according to config initial DMA controler if(err) printf("dma controler init fail\n"); else printf("dma controler init success\n"); XAxiDma_Reset(&InstancePtr); while(XAxiDma_ResetIsDone(&InstancePtr)==0); //waiting reset finish err = XAxiDma_SimpleTransfer(&InstancePtr, mm2s_buf1,(u32)32,0); //mm2s printf("err = %d\n",err); while(1){}DMA控制器在xilixi控制器中,主要是以下几步: 1、find config; 2、according to config initial DMA controler; 3、waiting reset finish; 4、waiting reset finish; 5、tranfer user data; 完成PS部分代码以后就可以进行硬件仿真了。 DMA MM2S (memory map to stream)数据流方向是从内存到stream,数据流的意思是数据的变化不是通过地址进行驱动的,而是在握手信号允许的条件下通过时钟进行去驱动的,下图是ila仿真时序图: MM2S_CNT是PS拷贝到DMA缓冲区数据,并且通过DMA控制器已经发送出去的数据。也就是fifo接收到的数据。 实际数据和缓冲区中的数据。这里为什么不是64位的数据呢? 其实是没问题的,这里定义的数组是u64的,但是数值在256以内,修改数组内容以后,看到的现象正常。 fifo计数器是慢一个时钟的,为什么? tlast是在数据结束的前一个时钟被置高为什么? tkeep代表了数据的有效性; DMA读取实验还在努力测试中,完成后再加上。
