1 前言
本文針對(duì)已經(jīng)對(duì)W5500有一定了解,并且數(shù)據(jù)手冊(cè)已經(jīng)通讀一遍的人群,因?yàn)椴┲髂壳爸煌瓿闪薝DP環(huán)回測(cè)試,因此在后文可能只介紹有關(guān)UDP部分。
2 前期準(zhǔn)備
1.FPGA核心板或者開(kāi)發(fā)板;
2.W5500模塊。下圖是博主使用的模塊;
3.網(wǎng)絡(luò)調(diào)試助手,網(wǎng)上隨便找一個(gè)就行;
3?。?500寄存器描述
主機(jī)與W5500通信有固定協(xié)議(數(shù)據(jù)幀),主機(jī)先發(fā)兩個(gè)字節(jié)的寄存器地址,然后一個(gè)字節(jié)的控制字,最后是數(shù)據(jù),這個(gè)數(shù)據(jù)可以是一個(gè)字節(jié),也可以是N的字節(jié),但是W5000為了方便操作,可以將這個(gè)N分為1、2、4和可變長(zhǎng)度,這些都可以配置。下圖是數(shù)據(jù)幀格式。
下圖是控制字段寄存器,BSB4~BSB0選擇寄存器,RWB是讀寫(xiě)選擇位(1:寫(xiě) 0:讀),OM選擇數(shù)據(jù)段中N的字節(jié)數(shù)。
W5500的寄存器分為兩種,一是通用寄存器,二是socket寄存器。這兩種寄存器通過(guò)數(shù)據(jù)幀中的地址段來(lái)選擇,如下圖所示。例如,當(dāng)寄存器地址為16’h0000時(shí),如果BSB是5‘h00000,那么此時(shí)選擇的是通用寄存器中的MR寄存器;如果BSB是5‘h00001,那么此時(shí)選擇的是socket0寄存器中的Sn_MR寄存器。
4?。?500 環(huán)回測(cè)試
4.1 W5500初始化
4.1.1 通用寄存器初始化
通用寄存器的初始化就是配置源網(wǎng)關(guān)、子網(wǎng)掩碼、MAC地址,IP地址、PHY寄存器,然后清中斷。
always@(posedge clk,negedge rst_n)
if(!rst_n)
o_dat<='d0;
else begin
case(state)
WR_MR://WRMR_CMD,
o_dat<=8'h00;
WRGAR_CMD,WR_GAR:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=GAR[31:24];
'd01:o_dat<=GAR[23:16];
'd02:o_dat<=GAR[15:08];
'd03:o_dat<=GAR[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_SUBR://WRSUBR_CMD,
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SUBR[31:24];
'd01:o_dat<=SUBR[23:16];
'd02:o_dat<=SUBR[15:08];
'd03:o_dat<=SUBR[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_SHAR://WRSHAR_CMD,
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SHAR[47:40];
'd01:o_dat<=SHAR[39:32];
'd02:o_dat<=SHAR[31:24];
'd03:o_dat<=SHAR[23:16];
'd04:o_dat<=SHAR[15:08];
'd05:o_dat<=SHAR[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_IP://WRIP_CMD,
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SIPR[31:24];
'd01:o_dat<=SIPR[23:16];
'd02:o_dat<=SIPR[15:08];
'd03:o_dat<=SIPR[07:00];
default:;
endcase
else
o_dat<=o_dat;
WRIR_CMD,WR_IR,WRIMR_CMD,WR_IMR:
o_dat<=8'hFF;
WR_RTR://WRRTR_CMD,
if(rdreq)
case(cnt_byte)
'd00:o_dat<=8'h07;
'd01:o_dat<=8'hD0;
default:;
endcase
else
o_dat<=o_dat;
WRRCR_CMD,WR_RCR:
o_dat<=8'h08;
WRPHY_CMD,WR_PHY:
o_dat<=8'b11111111;
default:o_dat<=8'h00;
endcase
end
4.1.2 socket寄存器初始化
socket寄存器配置跟通用寄存器類似,先配置目的socket模式(TCP、UDP、MACRAW)、MAC地址、目的IP地址、目的端口、以及本地端口等寄存器,然后清中斷等,最后配置Sn_CR寄存器打開(kāi)端口,之后就是定時(shí)查詢SN_SR寄存器,等待socket初始化成功(Sn_SR寄存器值為8’h22)。
always@(posedge clk,negedge rst_n)
if(!rst_n)
o_dat<='d0;
else begin
case(state)
WR_MR:
o_dat<=8'h02;
WR_IR,WR_IMR:
o_dat<=8'hFF;
WR_PORT:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SN_PORT[15:08];
'd01:o_dat<=SN_PORT[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_DHAR:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SN_DSHAR[47:40];
'd01:o_dat<=SN_DSHAR[39:32];
'd02:o_dat<=SN_DSHAR[31:24];
'd03:o_dat<=SN_DSHAR[23:16];
'd04:o_dat<=SN_DSHAR[15:08];
'd05:o_dat<=SN_DSHAR[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_DIPR:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SN_DIP[31:24];
'd01:o_dat<=SN_DIP[23:16];
'd02:o_dat<=SN_DIP[15:08];
'd03:o_dat<=SN_DIP[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_DPORT:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=SN_DPORT[15:08];
'd01:o_dat<=SN_DPORT[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_MSSR:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=8'h05;
'd01:o_dat<=8'hB4;
default:;
endcase
else
o_dat<=o_dat;
WR_CR:
o_dat<=8'h01;
default:;
endcase
end
4.2 W5500數(shù)據(jù)接收
軟件一直在查詢Sn_RX_RSR寄存器(Socket n 空閑接收緩存寄存器),顯示了 Socket n 接收緩存中已接收和保存的數(shù)據(jù)大小,當(dāng)其值大于0時(shí),表明socket已經(jīng)接收到數(shù)據(jù),因此可以進(jìn)行數(shù)據(jù)接收流程。W5500數(shù)據(jù)手冊(cè)提供了一種數(shù)據(jù)讀取的方法,如下圖所示。
socket的接收緩存(RX_BUF)有兩個(gè)指針,一是寫(xiě)指針(Sn_RX_WR)二是讀指針(Sn_RX_RD),當(dāng)外部將UDP數(shù)據(jù)發(fā)送給W5500時(shí),Sn_RX_WR會(huì)自動(dòng)增加,因此Sn_RX_WR是W5500芯片控制的。Sn_RX_RD由用戶控制,控制流程如上圖所示。
always@(posedge clk,negedge rst_n)
if(!rst_n)
o_dat<='d0;
else begin
case(state)
WR_RXRD:
if(rdreq)
case(cnt_byte)
'd00:o_dat<=rx_ptr[15:08];
'd01:o_dat<=rx_ptr[07:00];
default:;
endcase
else
o_dat<=o_dat;
WR_CR:
o_dat<=8'h40;
default:o_dat<=o_dat;
endcase
end
always@(posedge clk,negedge rst_n)
if(!rst_n)
rx_ptr<='d0;
else begin
case(state)
RD_RXRD:
if(rdrxrd_vld)
rx_ptr<=dinr;
else
rx_ptr<=rx_ptr;
RD_RXBUF:
if(den)
rx_ptr<=rx_ptr+'d1;
else
rx_ptr<=rx_ptr;
// END:
// rx_ptr<='d0;
default:rx_ptr<=rx_ptr;
endcase
end
4.3 W5500數(shù)據(jù)發(fā)送
軟件進(jìn)入數(shù)據(jù)發(fā)送流程時(shí),先查詢W5500的發(fā)送緩存剩余空間大小,如果剩余空間大于用戶發(fā)送數(shù)據(jù)長(zhǎng)度,那么繼續(xù)后續(xù)流程,反之則拒絕發(fā)送用戶數(shù)據(jù)。同樣,手冊(cè)也提供了一種數(shù)據(jù)發(fā)送的方法,如下圖所示。
4.4 數(shù)據(jù)環(huán)回
軟件例化例一個(gè)ram來(lái)存儲(chǔ)收到的數(shù)據(jù),接收完成后將數(shù)據(jù)讀出然后發(fā)送,代碼如下:
always@(posedge clk,negedge rst_n)
if(!rst_n)
state<='d0;
else begin
case(state)
IDLE:
if(rxdat_end && waddr>'d0)
state<=RDDAT_PRE;
else
state<=IDLE;
RDDAT_PRE:
state<=RD_DAT;
RD_DAT:
if(dat_tx_end)
state<=END;
else
state<=RD_DAT;
END:state<=IDLE;
default:state<=IDLE;
endcase
end
always@(posedge clk,negedge rst_n)
if(!rst_n)
dat_len<='d0;
else if(state==RDDAT_PRE)
dat_len<=waddr;
always@(posedge clk,negedge rst_n)
if(!rst_n)
o_dat_tx_req<='d0;
else if(state==RDDAT_PRE)
o_dat_tx_req<='d1;
else if(state==END)
o_dat_tx_req<='d0;
else
o_dat_tx_req<=o_dat_tx_req;
always@(posedge clk,negedge rst_n)
if(!rst_n)
waddr<='d0;
else if(rxdat_vld)
waddr<=waddr+'d1;
else if(state==END)
waddr<='d0;
always@(posedge clk,negedge rst_n)
if(!rst_n)
raddr<='d0;
else if(dat_tx_rden)
raddr<=raddr+'d1;
else if(state==END)
raddr<='d0;
my_ram
my_ram_inst (
.clock ( clk ),
.wren ( rxdat_vld ),
.wraddress ( waddr ),
.data ( rxdat ),
.rden ( dat_tx_rden ),
.rdaddress ( raddr ),
.q ( o_dat )
);
assign o_dat_len =dat_len;
最后測(cè)試結(jié)果如下圖所示,包含wireshark抓包結(jié)果。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-459370.html
5 總結(jié)
W5500的UDP通信是不難的,只要初始化正確,然后在收發(fā)時(shí)正確讀寫(xiě)socket寄存器,然后就沒(méi)啥難度了,手冊(cè)的話還是要多看幾遍,博主是在官網(wǎng)下載中文手冊(cè), W5500官網(wǎng)(手冊(cè)、參考電路、驅(qū)動(dòng)固件、例程等),完整代碼及工程放在評(píng)論區(qū)。
博主在完成UDP環(huán)回測(cè)試后還嘗試進(jìn)行TCP測(cè)試驗(yàn)證,W5500作為客戶端,但是在配置完成后發(fā)現(xiàn)W5500都沒(méi)有發(fā)出ARP包,后來(lái)就沒(méi)有測(cè)了,暫時(shí)先放下。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-459370.html
到了這里,關(guān)于FPGA控制W5500完成UDP環(huán)回測(cè)試的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!