易津开发板FPGA端环路测试代码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/snaking616/article/details/84539472

目录

1. 弄清Stream IN/OUT、端点EP2和EP6、USB读写操作之间的关系

2. FPGA内部FIFO控制逻辑

3. USB状态机分析

4. NIOS II控制代码分析

5. 附录


1. 弄清Stream IN/OUT、端点EP2和EP6、USB读写操作之间的关系

图1 上位机、USB端点和FPGA之间的数据流动示意图

如图1所示:

Stream IN表示从USB的EP6端点写入到PC端,

Stream OUT表示从PC端输出到USB的EP2端点。

USB端点相对PC而言:

EP6为一个输出FIFO,满标志位为FLAGC,为0时表示FIFO写满,将禁止FPGA向EF6内写入数据,

EP2为一个输入FIFO,满标志位为FLAGB,为0时表示FIFO为空,此时告诉FPGA端点EP2内无数据输出。

FPGA与USB之间:

FPGA往EP6内写入数据称为USB写操作,

FPGA向EP2内读取数据称为USB读操作。

2. FPGA内部FIFO控制逻辑

图2 FPGA内部FIFO引脚框图

图2中FIFO_From_USB为USB数据的接收FIFO,输入端位宽16bit,输出32bit,FIFO深度16bit*1024words,读写时钟异步。

r_rdreq为FIFO的写使能(高电平有效),ru_wrreq为FIFO的读使能(高电平有效),wrfull为FIFO的写满标志位,rdusedw[9:0]为FIFO可读的字数。

r_rdreq和ru_wrreq的约束条件如下:

assign ru_wrreq = (reset_n && ru_wrfull==1'b0 && usb_flagb==1'b1 && usb_address==2'b00&& STATE_NUM == USB_RDATA)?1'b1:1'b0;
assign r_rdreq = (chipselect_n==1'b0 && read_n==1'b0 && address==2'b00)?1'b1:1'b0;

图2中FIFO_To_USB为USB数据的发送FIFO,输入端位宽32bit,输出16bit,FIFO深度32bit*512words,读写时钟异步。

w_wrreq为FIFO的写使能(高电平有效),wu_rdreq为FIFO的读使能(高电平有效),rdempty为FIFO的读空标志位,wrusedw[9:0]为FIFO可写的字数。

w_wrreq和wu_rdreq的约束条件如下:

assign wu_rdreq = (reset_n && wu_rdempty==1'b0 && usb_flagc==1'b1 && usb_address==2'b10&& STATE_NUM ==USB_WDATA)?1'b1:1'b0;
assign w_wrreq = (chipselect_n==1'b0 && write_n==1'b0 && address==2'b00)?1'b1:1'b0;

3. USB状态机分析

图3 USB驱动代码的状态图

USB的FPGA驱动代码详见附录(1),该代码中状态机的状态图如下:

状态机的状态有3个,分为USB_IDLE、USB_RDATA、USB_WDATA,

(1)USB_IDLE状态下:

USB输出使能脚usb_sloe_n置1(只允许Stream OUT不允许Stream IN)。rul为USB读或写的检测开关,数值不停的在0和1之间翻转,当rul=1检测USB的读操作条件是否符合要求,rul=0时则检测USB写操作的条件是否符合要求。num的初始值为255,用于记录FPGA与USB之间传输16bit数据的次数,每记一次减1,不管是读还是写USB,当num=0时,表示USB端点对应的FIFO已经读空或者写满。

(2)USB_RDATA状态下:

该状态下,判断usb_flagb(EP2空标志位,1表示非空)是否为1且r_rdusedw(FPGA内部接收FIFO的已读字数)小于385,如果是打开接收FIFO的读使能ru_wrreq,同时USB读标志位usb_slrd_n置0,USB数据输出使能usb_sloe_n置0,FPGA进入USB数据的读状态。该状态下num在每个时钟上升沿减1,当num=0时,USB数据读操作终止,USB数据输出使能usb_sloe_n置1,状态切换至空闲模式。

(3)USB_WDATA状态下:

该状态下,判断usb_flagc(EP6满标志位,1表示没有满)是否为1且w_wrusedw(FPGA内部发送FIFO的已写字数)大于127,如果是打开发送FIFO的读使能wu_rdreq,同时USB写标志位usb_slwr_n置0,FPGA进入USB数据的写状态。该状态下num在每个时钟上升沿减1,当num=0时,USB数据写操作终止,状态切换至空闲模式。

补充说明:

USB写标志位usb_slwr_n和读标志位usb_slrd_n与接收FIFO的读使能ru_wrreq和发送FIFO的读使能wu_rdreq存在以下关系:

assign usb_slrd_n=~ru_wrreq;
assign usb_slwr_n=~wu_rdreq;

在读USB数据时,为什么要判断FPGA内部接收FIFO的已读字数r_rdusedw小于385?

答:确保接收FIFO内部还空余128*32bit的空间去存放USB端的16bit*256的数据。

在写USB数据时,为什么要判断FPGA内部发送FIFO的已写字数w_wrusedw大于127?

答:确保进行一次USB写操作之前,FPGA内部发送FIFO至少存有128*32bit的数据。

4. NIOS II控制代码分析

核心控制代码如下

unsigned long buf[128];
static void ISR_timer(void *context, alt_u32 id) 
{ 
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x07);
    if(PIO_USB->READ_COUNT>127 && PIO_USB->WITRE_COUNT<385)
    {
        XferData(buf,128,1);
        XferData(buf,128,0);
    }
    IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x00);
};

int main()
{ 
    usleep(500000);
    U_EmptyFIFO();
    IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x00);
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x07);
    alt_irq_register(TIMER_0_IRQ, (void *)TIMER_0_BASE, ISR_timer);
    while(1);
    return 0;
}

控制思路为:清空FIFO-->初始化时钟中断-->死循环-->调用时钟中断子程序-->FIFO数据读写操作。

与NIOS中代码:PIO_USB->READ_COUNT>127 && PIO_USB->WITRE_COUNT<385、pData[Count]=PIO_USB->DATA;和
  
PIO_USB->DATA=pData[Count];

配合的Verilog代码如下:

assign read_data    =    (chipselect_n    ==    1'b0 && read_n    ==    1'b0)?((address==2'b00)?r_q:
                                                                                    ((address==2'b01)?{22'd0,r_rdusedw}:
                                                                                    ((address==2'b10)?{22'd0,w_wrusedw}:
                                                                                    {30'd0,usb_flagb,usb_flagc}))):32'h0;
  其中:

PIO_USB->READ_COUNT对应r_rdusedw,

PIO_USB->WITRE_COUNT对应w_wrusedw,

PIO_USB->DATA对应接收FIFO的q[31:0]r_q或者发送FIFO的data[31:0]。

5. 附录

(1)USB的FPGA驱动代码YJUSB.v:

module YJusb(clk,
	reset_n,					
	chipselect_n,
	address,
	read_n,					
	read_data,					
	write_n,	
	write_data,
	redyfordata,
	dataavailable,
	endofpacket,					
	usb_ifclk,
	usb_slrd_n,
	usb_slwr_n,
	usb_sloe_n,
	usb_flagb,
	usb_flagc,
	usb_pkend,
	usb_data,
	usb_address,
	usb_clk);
//----------------------------------------------------------------
input clk,usb_clk;
input reset_n;
input chipselect_n;
input [1:0]address;
input read_n;
output [31:0]read_data;
input write_n;
input [31:0]write_data;
//---------------------------------
output redyfordata;
output dataavailable;
output endofpacket;
//---------------------------------
output usb_ifclk;
output usb_slrd_n;
output usb_slwr_n;
output usb_sloe_n;
input usb_flagb;
input usb_flagc;
output usb_pkend;
inout  [15:0]usb_data;
output [1:0]usb_address;
reg usb_sloe_n;
reg [1:0]usb_address;
//----------------------------------------------------------------
//reg [15:0]pkendcount;
//----------------------------------------------------------------
parameter USB_IDLE    = 4'd0; 
parameter USB_RIREADY	= 4'd1; 
parameter USB_WIREADY	= 4'd2; 
parameter USB_RDATA   = 4'd3; 
parameter USB_WDATA   = 4'd4; 
//parameter USB_PKEND   = 3'd5; 
//----------------------------------------------------------------
reg [3:0] STATE_NUM;
//parameter ENDPOINT2  = 2'b00; 
//parameter ENDPOINT4  = 2'b01; 
//parameter ENDPOINT6  = 2'b10; 
//parameter ENDPOINT8  = 2'b11; 
//----------------------------------------------------------------
wire [9:0] w_wrusedw;
//----------------------------------------------------------------
wire [31:0] r_q;
wire [9:0] r_rdusedw;
wire r_rdreq;
wire ru_wrreq;
wire ru_wrfull;
wire wu_rdempty;
wire w_wrreq;
wire [15:0] wu_q;
wire wu_rdreq;
reg rul;
//----------------------------------------------------------------
FIFO_From_USB fifo_from(usb_data,clk,r_rdreq,usb_ifclk,ru_wrreq,r_q,r_rdusedw,ru_wrfull);
FIFO_To_USB fifo_to(write_data,usb_ifclk,wu_rdreq,clk,w_wrreq,wu_q,wu_rdempty,w_wrusedw);
//----------------------------------------------------------------
reg [7:0]num;
always@(posedge usb_ifclk or negedge reset_n)
begin
   if (!reset_n) begin	
			STATE_NUM <= USB_IDLE;
			rul<= 1'd1;
			usb_sloe_n<=1'd1;
			num<=8'h0;
			end
   else	begin
	    case(STATE_NUM)
	    USB_IDLE:	begin
		   rul<=~rul;
		   num<=8'hff;
		   if(rul)
			    begin	
			    if(usb_flagb && r_rdusedw<10'h181)
			    begin
			    STATE_NUM<=USB_RDATA;
			    usb_address<=2'b00;
			    usb_sloe_n<=1'd0;
			    end
		end
		else
			begin	
			if(usb_flagc && w_wrusedw>10'h7f)
				begin
				STATE_NUM<=USB_WDATA;
				usb_address<=2'b10;
				end
			end
		end					
    USB_RDATA:	begin
			if(num==8'h0)	
				begin
				STATE_NUM<=USB_IDLE;
				usb_sloe_n<=1'd1;
				end
			else	num<=num-8'h1;
			end
	USB_WDATA:	begin
			if(num==8'h0)	
				begin
				STATE_NUM<=USB_IDLE;
				end
			else	num<=num-8'h1;					
			end
			default:;
			endcase
			end
end
assign wu_rdreq = (reset_n && wu_rdempty	==	1'b0 && usb_flagc	==	1'b1 && usb_address==2'b10	&& STATE_NUM == USB_WDATA)?1'b1:1'b0;
assign w_wrreq = (chipselect_n	==	1'b0 && write_n	==	1'b0 && address==2'b00)?1'b1:1'b0;
assign ru_wrreq = (reset_n && ru_wrfull	==	1'b0 && usb_flagb	==	1'b1 && usb_address==2'b00	&& STATE_NUM == USB_RDATA)?1'b1:1'b0;
assign r_rdreq = (chipselect_n	==	1'b0 && read_n	==	1'b0 && address==2'b00)?1'b1:1'b0;
assign read_data	=	(chipselect_n	==	1'b0 && read_n	==	1'b0)?((address==2'b00)?r_q:
																					((address==2'b01)?{22'd0,r_rdusedw}:
																					((address==2'b10)?{22'd0,w_wrusedw}:
																					{30'd0,usb_flagb,usb_flagc}))):32'h0;
assign usb_slrd_n=~ru_wrreq;
assign usb_slwr_n=~wu_rdreq;
//----------------------------------------------------------------
assign endofpacket=1'b0;
assign redyfordata=  1'b1;
assign dataavailable=  1'b1;
//----------------------------------------------------------------
assign usb_pkend=1'b1;
//----------------------------------------------------------------
assign usb_ifclk=usb_clk;
//----------------------------------------------------------------
assign usb_data= (STATE_NUM == USB_WDATA)?wu_q:16'hzzzz;
endmodule

(2) NIOS II代码:

main.c


#include <stdlib.h>
#include <stdio.h>
#include "string.h"
#include <unistd.h>
#include "altera_avalon_timer_regs.h"
#include "alt_types.h"
#include "sys/alt_irq.h"
#include "../inc/usb.h"
#include "../inc/io.h" 

unsigned long buf[128];
static void ISR_timer(void *context, alt_u32 id) 
{ 
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x07);
    PIO_0->DATA=~PIO_0->DATA;   
    PIO_1->DATA=~PIO_1->DATA;   
    PIO_2->DATA=~PIO_2->DATA;     
    if(PIO_USB->READ_COUNT>127 && PIO_USB->WITRE_COUNT<385)
    {
        XferData(buf,128,1);
        XferData(buf,128,0);
    }
    IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x00);
};

int main()
{ 
    usleep(500000);
    U_EmptyFIFO();
    PIO_0->DATA=0xffffffff;   
    PIO_1->DATA=0xffffffff;  
    PIO_2->DATA=0xffff;
    IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_0_BASE, 0x00);
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_0_BASE, 0x07);
    alt_irq_register(TIMER_0_IRQ, (void *)TIMER_0_BASE, ISR_timer);
    while(1);
    return 0;
}

usb.h

#ifndef USB_H_
#define USB_H_
#include "system.h"
#include "string.h"
#define USB_BUF_MAX_SIZE 256
typedef struct
{
    unsigned long int DATA;
    unsigned long int READ_COUNT;
    unsigned long int WITRE_COUNT;
    unsigned long int NC;
}IO_USB;
#define PIO_USB ((IO_USB *)(YJUSB_0_BASE | (1 << 31)))
int XferData(unsigned long *pData,unsigned long nCount,short rw);
void U_EmptyFIFO(void);
void U_FullFIFO(void);
#endif /*USB_H_*/

usb.c

#include "../inc/usb.h"
#include <unistd.h>
int XferData(unsigned long *pData,unsigned long nCount,short rw)
{
    unsigned long Count=0;
    if(rw)
    {
        for(;Count<nCount;Count++)
        { 
            pData[Count]=PIO_USB->DATA;
        }
    }
    else
    {
        for(;Count<nCount;Count++)
        { 
            PIO_USB->DATA=pData[Count];
        }
    } 
    return (int)Count;
};
void U_EmptyFIFO(void)
{
    unsigned long Count=PIO_USB->READ_COUNT; 
    unsigned long buf=0;
    unsigned long n;
    for(n=0;n<Count;n++)
    {
        buf=PIO_USB->DATA;
    }
};
void U_FullFIFO(void)
{
    unsigned long Count=512-PIO_USB->WITRE_COUNT; 
    unsigned long buf=0x5a5a5a5a;
    unsigned long n;
    for(n=0;n<Count;n++)
    {
        PIO_USB->DATA=buf;
    }
};

参考:无

猜你喜欢

转载自blog.csdn.net/snaking616/article/details/84539472