ZYNQ AXI DMA调试细节

1 篇文章 0 订阅
0 篇文章 0 订阅

---------------------  已经征得作者同意
作者:同年纪_  
来源:CSDN  
原文:https://blog.csdn.net/q774318039a/article/details/88377135  
版权声明:本文为博主原创文章,转载请附上博文链接!

---------------------  

其他介绍部分省略,摘抄部分内容如下:(要了解更多详情,请参考原文链接。)

本人问题:在实际接收中,数据从AD产生经过fifo到达AXI DMA。然后不论是linux还是sdk调试,axidma的接收都会出错。出错时,接收状态寄存器都是同一值,读0x58为0x5011。经过调试,以及搜索发现的有用的帖子摘抄如下

转载帖子摘抄如下(引用是作者原文,未改动)成果待验证。

4. DMA何时才会接收结束?

DMA的读写接口都是axis stream,是强制有tlast的,就是靠tlast信号来判断接收结束的,而不是填写的length值。发送接收值,最后一个tdata会同时伴随一个tlast高电平。接收时,设置接收5000字节,并不是说接收满5000个字节就结束了,而是开启接收后,接收到1个tlast高电平就结束了,也就是说,你可能会只接收到2000个字节,手册中明确说了,当设置的length = 0,或者接收到的数据大于设置的length,就会引起DMAIntErr置1,接收错误。

所以,当设置每次接收5000字节时,tlast就应该每隔<5000字节时插入。我的应用中,DMA前是一个AXIS DATA FIFO,写入是自定义的时序,但接收时还是报错,接收得太多了。为什么呢?因为DMA是自己拉高tready,而fifo的valid也为高就开始计数了,跟FIFO随后的valid 无关(我瞎猜的),DMA读的速度远高于我写入速度,我还没写到tlast,DMA就计数到16383了,DMA就报错,怎么办呢,开启fifo的packet模式。然后DMA接收就ok了。

5. 实际应用

DMA的使用上我遇到的坑,实际上就是地址对齐,tlast的给定上,因为我每次接收完后都会reset下,导致看不出来dma哪儿有问题,但数据总是不对。

DMA的发送一般没有什么问题,有个小技巧,可以用DMA的reset_out引脚去初始化fifo,我有一个应用就2个dma交替发送数据到pl的2个fifo,fifo的存取上老有问题,写768个字节,读768个字节,fifo有时还会有留存数据,导致下一次取数据多了一个,也没细想过问题,DMA发送前先复位一下,顺便把fifo复位一下,就解决这个问题。

另一个应用是pl采集spi的数据,但数据不知道什么时候来,每一包也不知道有多少个字节。我在ps中开了一个定时器,1ms一次,开定时器前,先开启DMA接收,在定时器中断中查询是否接收完成(idle),idle后就把接收地址base_addr加上1个length,再开启下一次传输。而pl端,每隔4096个字节就插一个tlast。又有一个问题,要是有5000个字节呢?剩下的4个怎么办?我又加了个定时器,超过2s,没有数据来,且fifo的data_count不等于0,我就加入aa aa aa数据,并在最后一个aa时拉高一次tlast,表示一次传输完成。在ps端,开启freertos多线程,设置一个send_addr和base_addr初始值相同,当send_addr小于base_addr时,用udp把数据发送出去。又有一个问题,base_addr不能一直往上上加啊,加到大于某个值的时候,且send_addr = base_addr,把数据拷贝到初始值去,重置这2个指针。

    void Timer_ISR(void *CallBackRef)
    {
        lock = 1;
        if(Xil_In32(0x40400000 + 0x34) & 0x02) //idle = 10
        {
            Xil_DCacheFlushRange(base_addr,Xil_In32(0x40400000 + 0x58));
        //    xil_printf("length is %d\r\n",Xil_In32(0x40400000 + 0x58));
            unsigned int len = Xil_In32(0x40400000 + 0x58);
            if((send_addr == base_addr) &&(send_addr != 0x1000000) && (base_addr >= 0x1F400000))
            {
                memcpy(0x1000000,base_addr,len);// dest,src,len
                base_addr = 0x1000000;
                send_addr = 0x1000000;
                base_addr = base_addr + len;
                Xil_Out32((0x40400000 + 0x48),base_addr); //set da address
                Xil_Out32((0x40400000 + 0x58),8192); //set da address
            }
            else
            {
                base_addr = base_addr + len;
                Xil_Out32((0x40400000 + 0x48),base_addr); //set da address
                Xil_Out32((0x40400000 + 0x58),8192); //set da address
            }
     
        }
        lock = 0;
    //    xil_printf("count is %d\r\n",XGpio_DiscreteRead(&COUNT,1));
    //    xil_printf("CR is %d\r\n", Xil_In32(0x40400000 + 0x30));
    //    xil_printf("SR is %d\r\n", Xil_In32(0x40400000 + 0x34));
    //    xil_printf("LENGTH is %d\r\n", Xil_In32(0x40400000 + 0x58));
    }

要注意DMA操作DDR3,CPU是不知道的,要用dcacheflush及时刷新。这个刷新速度很慢的,要注意控制刷新的长度。

        while(1)
        {
            if(lock == 0)
            {
                if(send_addr < base_addr)
                {
                    unsigned int len = base_addr - send_addr;
                    if(len > 16384)
                        len = 16384;
                    msg_udp_send((UINTPTR)send_addr,len);
                    send_addr = send_addr + len;
                }
     
            }
            vTaskDelay(10);
        }

    always@(posedge clk)
        if((!en) ||(delay_over == 32'd400_000_000))
            byte_cnt <= 1'd0;
        else if(tvalid)
        begin
            if(byte_cnt == 32'd4095)
                byte_cnt <= 1'd0;
            else
                byte_cnt <= byte_cnt + 1'd1;
        end
        
        assign m_axis_tlast = (tvalid && (byte_cnt == 32'd4095 || i == 8'd13))?1'd1:1'd0;
        
        
        reg [31:0] delay_over = 1'd0;
        assign mode = reg_mode;
        always@(posedge clk)
        if(!en)
            begin
                i <= 1'd0;
                reg_mode <= 1'd0;
                tvalid <= 1'd0;
                tdata <= 1'd0;
            end
        else
            case(i)
            0:
            if(cs_fall_edge && m_axis_tready&&(fifo_count <= 32'd36700) ) //fifo ready && cs fall
            begin
                i <= i + 1'd1;
                delay_over = 1'd0;
            end
            else if(fifo_count != 1'd0)
            begin
                if(delay_over == 32'd400_000_000) //超时2s
                    begin
                        delay_over = 1'd0;
                        i <= 8'd10;
                    end
                else
                    delay_over = delay_over + 1'd1;
            end
            1:
            if(data_cs)
                i <= 1'd0;
            else if(valid)
                begin
                    case (data)
                    8'h03,8'h0b:
                        reg_mode <= 4'd0;   
                    8'h05,8'h9f:
                        reg_mode <= 4'd1;
                    default:
                        reg_mode <= 4'd1;
                    endcase
                    i <= i + 1'd1;
                end
            else
                i <= i;
            2:
            begin
                tvalid<= 1'd1;
                tdata <= 8'hee;
                if(m_axis_tready&&(fifo_count <= 32'd36700))
                    i <= i + 1'd1;
                else
                    i <= 8'd7;
            end
            3:
            begin
                tvalid<= 1'd1;
                tdata <= 8'h55;
                if(m_axis_tready&&(fifo_count <= 32'd36700))
                    i <= i + 1'd1;
                else
                    i <= 8'd7;
            end
            4:
            begin
                tvalid<= 1'd1;
                tdata <= data;
                if(m_axis_tready&&(fifo_count <= 32'd36700))
                    i <= i + 1'd1;
                else
                    i <= 8'd7;
            end
            5:
            begin
                tvalid<= 1'd0;
                i <= i + 1'd1;
            end
            6:
            if(data_cs)
               i <= i + 1'd1;
            else if(valid)
                begin
                    tvalid<= 1'd1;
                    tdata <= data;
                    if(m_axis_tready&&(fifo_count <= 32'd36700))
                        i <= 8'd5;
                    else
                        i <= 8'd7;
                end
            else
                i <= i;
            7:
            begin
                tvalid<= 1'd1;
                tdata <= 8'haa;
                i <= i + 1'd1;
            end
            8:
            begin
                tvalid<= 1'd0;
                i <= i + 1'd1;
                if(isr_en)
                    isr_start <= 1'd1;
            end
            9:
            begin
                i <= 1'd0;
                isr_start <= 1'd0;
            end
            10,11,12:
            begin
                tvalid<= 1'd1;
                tdata <= 8'haa;
                i <= i + 1'd1;
            end
            13:
            begin
                tvalid<= 1'd0;
                i <= 1'd0;
            end
            default:   
            i <= 1'd0;
            endcase
            
     
           assign m_axis_tvalid =  tvalid;
           assign m_axis_tdata  =  tdata;

坑有无数,愿你抗住!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值