|
发表于 2009-11-30 05:13:58
|
显示全部楼层
没必要这么害怕USB,FPGA的3V3的IO接USB的D+/D-,完成FS USB的功能还是可行的(FS/LS USB根本没有想象中的那么复杂,Mass Storage的类协议另说,那个稍微复杂点,我见过);
HS的话,有收发器的才有可能,要不就外接个Phy.
来段示例(FS USB物理层的大部分,除了Resume方面的),不然有人会不信:
// Hey, Emacs! This is a -*- verilog -*- file.
/* CRC module generator
*
* These people at Intel should be shot. This is not how a CRC should
* look like. I found out a trick to make it to be as compact as possible,
* but I still don't like it. For the 5 bit CRC, going for a zero residual
* is possible, but for the 16 bit CRC, you can't know when the packet ends,
* so you have to check for the residual (inverted here). When sending, the
* residual is zero in any case.
*/
module usb_crc(clk, usbclk, reset, en, send, tx, crc16, out, val);
input clk, usbclk, reset, en, send, tx, crc16;
output out, val;
reg [15:0] crc;
assign out = crc16 ? crc[15] : crc[4];
assign val = crc16 ? (crc == 16'h7FF2) : (crc[4:0] == 5'h00);
always @(posedge clk or negedge reset)
if(!reset)
crc <= 16'h0000;
else if(en & `AT_BIT)
crc <= { crc[14:0], ~send } ^ ((~send ^ tx ^ out) ? 16'h8005 : 16'h0);
endmodule // usb_crc
/* Bit handling
*
* This handles the bit serial part. Four times oversampling is used to
* get more reliable data. The actual transition phase is ignored.
* This module also delivers a bit clock, which is a digitally locked
* PLL signal, locked on the transition. EOP detection happens here, too.
* Finally, it also flags bit stuffing
*/
module usb_bit(clk, reset, dif, se0, send,
bitclk, bitin, stuff, endp);
input clk, reset, dif, se0, send;
output bitclk, bitin, stuff, endp;
reg [3:0] oversample;
reg [4:0] bitcount;
reg [2:0] eop;
reg bitin;
wire [3:0] phase = 1 << bitcount[1:0];
assign stuff = bitcount[4:2] == 3'h7;
assign bitclk = phase[0];
assign endp = send ? &eop : eop[2];
always @(posedge clk or negedge reset)
if(!reset) begin
oversample <= 4'b1111;
bitcount <= 5'b11111;
eop <= 3'b000;
bitin <= 1;
end else begin
eop <= se0 ? eop + ~&eop : 3'b000;
oversample <= endp ? 4'b1111 : { oversample[2:0], dif };
bitcount <= endp ? 5'h1F : bitcount + (send | ~&bitcount);
if(|bitcount[4:2]) begin
if((oversample[3] == oversample[2]) &&
(oversample[2] != oversample[0]) &&
(oversample[0] == dif) && !phase[0])
begin
if(!stuff || bitcount == 5'h1F)
bitin <= 1'b0;
bitcount <= 5'h02;
end
else if(phase[3] && |bitcount[4:2] && ~&bitcount[4:2])
bitin <= 1'b1;
end
end
endmodule // usb_bit
/* Byte handling
*
* This handles byte edge detection. A byte clock is delivered,
* and a indication when crc5 sending/receiving happens.
*/
module usb_byte(clk, usbclk, reset, bit, stuff, eop, send, nextbyte,
byte, byteclk, crc5, bytetop);
input clk, usbclk, reset, bit, stuff, eop, send;
input [7:0] nextbyte;
output [7:0] byte;
output byteclk, crc5, bytetop;
reg [7:0] byte;
reg [3:0] count;
wire count_rst = reset & ~eop;
assign byteclk = ~|count[2:0];
assign crc5 = count > 4'hA;
assign bytetop = count[3];
always @(posedge clk or negedge count_rst)
if(!count_rst) begin
count <= 0;
end else if(!stuff & `AT_BIT) begin
count <= count + 1;
end
always @(posedge clk or negedge reset)
if(!reset) begin
byte <= 8'h00;
end else if(!stuff & `AT_BIT) begin
byte <= send & byteclk ? nextbyte : { bit, byte[7:1] };
end
endmodule // usb_byte
/* Receiving state
*
* USB can either wait for a sync byte
* read in the PID
* or read in data
* or be in an error state
*
* State is reset by eop or USB reset
*
* After transmission is completed successfull,
* ok is set.
*/
module usb_state(clk, reset, eop, crc, crc5, byte, byteclk, send,
state, ok);
parameter show=0;
input clk, reset, eop, crc, crc5, byteclk, send;
input [7:0] byte;
output [1:0] state;
output ok;
reg [1:0] state;
reg ok;
wire state_rst = reset & ~eop;
always @(posedge clk or negedge state_rst)
if(!state_rst) begin
state <= 2'b00;
if(show) $display("eop");
end else if(`AT_BYTE) begin
case(state)
2'b00: begin
if(send | byte == 8'h80) begin
state <= 2'b01; // pid state
end
end
2'b01: begin
if(send || byte[3:0] != 0 || (~byte[7:4]) == byte[3:0]) begin
state <= 2'b10; // data state
end else begin
state <= 2'b11; // error state
end
end
2'b10: begin
if(crc5) state <= 2'b11; // error state
end
endcase // case(state)
end
always @(posedge clk or negedge reset)
if(!reset) begin
ok <= 0;
end else if(`AT_BYTE) begin
case(state)
2'b00: ok <= 1;
2'b10: begin
ok <= crc;
if(show & crc) $display("packet ok");
end
endcase // case(state)
end
endmodule // usb_state |
|