ZYNQ AXI_DMA_UDP以太网传输(二)问题记录
上一篇文章只是简单的记录一下调试成功的代码
但调试成功这个过程很痛苦,踩了很多坑,特此记录,留眼以后查看
问题1:DMA传输过程中报错 dma error
参考博客
xilinx dma调试笔记
ZYNQ AXI DMA调试细节
在调试过程中出现这类问题基本上都是这一句代码出了问题:
axi_dma_start(MAX_PKT_LEN);
再往里面跳可以看见这样一个函数,在正点原子提供的例程中是这样的
status = XAxiDma_SimpleTransfer(&axidma, (u32) rx_buffer_ptr,
pkt_len, XAXIDMA_DEVICE_TO_DMA);
出现报错基本上都是因为pkt_len设置的太小,按照xilinx dma调试笔记的说法就是**“问题是设置传输的S2MM buffer length太小”“这里读出0x5011表示例化DMA的时候配置的S2MM buffer length太小,导致DMA在接收buff满的时候还没有遇到last信号,就会产生DMAIntErr错误”**
最开始的时候我在ip核中设置的位宽是23位,那么我想着那我就把这个MAX_PKT_LEN(也就是pkt_len)设置为2^23-1,这么一改之后确实没有报错了,dma跑通了,但是我还是有些奇怪,为什么不能太小呢,具体的范围有吗?
后来我看到评论里的**“这里读出0x5011表示例化DMA的时候配置的S2MM buffer length太小,导致DMA在接收buff满的时候还没有遇到last信号,就会产生DMAIntErr错误”**突然悟了,仔细看我的数据产生模块代码,产生2048个32bit的数据后才会产生一个时钟周期的tlast信号,如果我把MAX_PKT_LEN设置的调小,这里的dma传输的是一个字节,相当于8bit,按照之前的设置MAX_PKT_LEN=2048,那肯定接收不到talst信号呀,所以肯定会报错的,所以有一种改法是,不动正点原子的代码,增加MAX_PKT_LEN,因为产生2048个32bit的数据后才会产生一个时钟周期的tlast信号,所以其实是传递8192个字节后产生talst信号,于是MAX_PKT_LEN需要大于等于8192!这么一改果然对了!兴奋!当然还有一种改法,那就是【JokerのZYNQ7020】AXI_DMA_PL_PS最下面说的那样"所有涉及MAX_PKT_LEN的地方,都要*sizeof(u32) ;" 一开始还不是很理解,这时候才恍然大悟,所以在我自己的代码里这一部分改成了
status = XAxiDma_SimpleTransfer(&axidma, (u32) rx_buffer_ptr,
(u32)(pkt_len*sizeof(u32)), XAXIDMA_DEVICE_TO_DMA);
之后我再设置MAX_PKT_LEN只需要设置为2048就行了
问题2:DMA传输过程中第一次传输的数据总是从5开始
这个问题本来其实是打算忽略的,因为除了第一次传输,之后的传输又都是从1开始传输的,但是想着留在这里始终是个刺,还是研究一下吧,没想到一研究发现这个问题有点恼火。
我最开始的数据产生模块的代码中的状态机转移其实是这么写的:
always @(*) begin
case(r_current_state)
IDLE : r_next_state = ( M_AXIS_tready) ? TRAN : IDLE;
TRAN : r_next_state = (r_M_AXIS_tdata == TRANS_NUM) ? LAST : TRAN;
LAST : r_next_state = M_AXIS_tready ? IDLE : LAST;
default : r_next_state = IDLE;
endcase
end
表面上看没什么问题,但是按照这么写每次第一次传输都从5开始,我就很奇怪,于是去ila抓信号查看,我发现我一进入debug,首先不急着单步调试,而是直接在ila界面强制触发,发现信号如下图所示:
从图中可以看出,我的代码还没运行,但是FPGA内部好像已经满足了我代码里的状态转移条件,一开始就是个5,但是我一看M_AXIS_tready信号又是低电平,M_AXIS_tvalid信号又是高电平,这就给我整不会了,难道是在上电过程中M_AXIS_tready有高电平的时刻?然后因为进入到了TRAN状态,在这个状态下,tvaild信号为高电平,随即tvaild和tready进行握手,tready信号拉低,等待dma传输将tready拉高。
为了验证这个猜想,我首先注释掉了TRAN状态下的tvalid信号
TRAN : begin
// r_M_AXIS_tvalid <= 1'd1;
if(M_AXIS_tready)begin
r_M_AXIS_tdata <= r_M_AXIS_tdata + 32'd1;
if(r_M_AXIS_tdata == TRANS_NUM)
r_M_AXIS_tlast <= 1'd1;
else
r_M_AXIS_tlast <= 1'd0;
end
else
r_M_AXIS_tdata <= r_M_AXIS_tdata;
end
然后跑ila发现,
数据一直在累加,M_AXIS_tready一直是1!!!!这证明了部分猜想,可能是因为进行了握手才导致M_AXIS_tready拉低的,但是我又改怎么避免误触发呢?最后是参考了博客ZYNQ通过AXI DMA实现PL发送连续大量数据到PS DDR
的写法
always @(*) begin
case(r_current_state)
IDLE : r_next_state = (pos_trans_start && M_AXIS_tready) ? TRAN : IDLE;
TRAN : r_next_state = (r_M_AXIS_tdata == TRANS_NUM) ? LAST : TRAN;
LAST : r_next_state = M_AXIS_tready ? IDLE : LAST;
default : r_next_state = IDLE;
endcase
end
触发条件增加一个上升沿,这样子就能解决这个bug了。
问题3:网口调试助手连接不上指定端口
对于这个问题我是真无语。。。一开始我用正点原子的教程,跟着一步一步走,但是最后就是连接不上
最后查了下最下面的报错信息才意识到可能是端口号被占用了用不了,好家伙,结果我去查怎么查看电脑被占用的端口号,结果真占用了…于是我去招了个没被占用的端口号,一试就成了,还是不能生搬硬套。
其实还有遇到很多问题,比如:文章来源:https://www.toymoban.com/news/detail-839661.html
- 根据csdn中的要求,axi fifo最好打开packet模式
- 提供数据的模块必须产生tlast信号给axi
fifo,否则会没有数据,这也就要求提供数据的模块外围得包装一个axi协议相关的架构,包括tlast,ready、valid、keep等 - 使用以太网传输前需要确定自己的电脑哪些端口可用,否则会出现端口被占用导致无法网口调试的情况,如何查看被占用的端口可百度。
- 正点原子提供的udp发数据的代码有个bug,传输数据是写死的,自己需要简单改成变量。 另外自定义的axi数据模块的时钟命名会影响block design的验证:不能定义为i_clk(无语)
一开始遇到这些问题真的是好折磨,但后面解决完了回过头看还是很有收获的,bug就是让人成长的(笑死)。文章来源地址https://www.toymoban.com/news/detail-839661.html
到了这里,关于ZYNQ AXI_DMA_UDP以太网传输(二)问题记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!