测试E2PROM,即93C46
1) 93C46是一个有128字节的eeprom,可以是8位或16位的存储模式,在RTL8019AS中,用的是16位的模式,也就是总共有64个16位的存储单元.16位方式下,存储地址为0---63 .每个地址存储两个字节,低位字节在前,高位字节在后(这跟单片机的存储相反,单片机是高位在前,低位在后).
8位或者16位通过管脚硬件选择
8位时,地址位只有7位
2)写需要执行3个93c46命令:
.EWEN command写使能
.WRITE command写数据
.EWDS command禁止写
3)
将spi时钟反相后给E2PROM,(93C46数据的读入和读出都是在时钟的上升沿,直接将控制器中使用的上升沿时钟赋值给93C46,可能会由于走线问题或者保持时间不够而造成时序混乱,比如数据比片选来的要早等等)。
读出数据时,其datasheet已指明,数据在时钟上升沿翻转,所以控制器接收数据要用93C46时钟的反相,这样时钟上升沿正对数据稳定的中心;
读出数据时,第一个数据固定为0,后面的8位才是有效数据
4) 代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module E2PROM_TOP(
input clkin,
input mi,
input write,
input read,
output sck,
output reg cs,
output reg mo,
output TEST
);
//generate spi clk
parameter div = 40;
reg [5:0] div_cnt = 6'b0;
reg spi_clk = 1'b0;
always @ (posedge clkin)
begin
if(div_cnt == div) div_cnt <= 6'b0;
else div_cnt <= div_cnt + 1;
end
always @ (posedge clkin)
begin
if(div_cnt == div/2) spi_clk <= !spi_clk;
else if(div_cnt == div) spi_clk <= !spi_clk;
else spi_clk <= spi_clk;
end
assign sck = !spi_clk;
//generate rst
reg rst = 1'b0;
reg [7:0] rst_cnt = 8'b0;
always @ (posedge clkin)
begin
if(&rst_cnt) rst_cnt <= rst_cnt;
else rst_cnt <= rst_cnt + 1;
end
always @ (posedge clkin)
begin
if(&rst_cnt) rst <= 1'b0;
else rst <= 1'b1;
end
//generate true_write
reg [1 : 0] write_s = 2'b0;
reg [29 : 0] write_cnt = 30'b0;
reg true_write = 1'b0;
always @ (posedge spi_clk)
begin
write_s <= {write_s,write};
end
always @ (posedge spi_clk)
begin
if(rst) write_cnt <= 30'b0;
else if(write_s == 2'b11) write_cnt <= write_cnt + 1;
else write_cnt <= 30'b0;
end
//
always @ (posedge spi_clk)
begin
if(rst) true_write <= 1'b0;
else if(true_write) true_write <= 1'b0;
else if(&write_cnt[12:0]) true_write <= 1'b1;
else true_write <= 1'b0;
end
//generate true_read
reg [1 : 0] read_s = 2'b0;
reg [29 : 0] read_cnt = 30'b0;
reg true_read = 1'b0;
always @ (posedge spi_clk)
begin
read_s <= {read_s,read};
end
always @ (posedge spi_clk)
begin
if(rst) read_cnt <= 30'b0;
else if(read_s == 2'b11) read_cnt <= read_cnt + 1;
else read_cnt <= 30'b0;
end
//
always @ (posedge spi_clk)
begin
if(rst) true_read <= 1'b0;
else if(true_read) true_read <= 1'b0;
else if(&read_cnt[12:0]) true_read <= 1'b1;
else true_read <= 1'b0;
end
//***********************************************************
//state
parameter idle = 2'b00,
s_write = 2'b01,
s_read = 2'b10;
reg [1 : 0] state = 2'b0;
reg [9 : 0] ewen_data = 10'b100_1100000;
reg [17 : 0] write_data = 18'b101_0111111_01011010;
reg [9 : 0] ewds_data = 10'b100_0000000;
reg [9 : 0] write_data_rd = 10'b110_0111111;
reg [7 : 0] read_data;
reg [5 : 0] wr_state_cnt = 5'b0;
reg [4 : 0] rd_state_cnt = 5'b0;
//state
always @ (posedge spi_clk)
begin
if(rst) state <= idle;
else
case(state)
idle:
begin
if(true_read) state <= s_read;
else if(true_write) state <= s_write;
end
s_read: state <= (rd_state_cnt == 5'd19) ? idle : s_read;
s_write: state <= (wr_state_cnt == 6'd50) ? idle : s_write;
endcase
end
//wr_state_cnt
always @ (posedge spi_clk)
begin
if(rst) wr_state_cnt <= 6'b0;
else if(state == s_write) wr_state_cnt <= wr_state_cnt + 1;
else wr_state_cnt <= 6'b0;
end
//rd_state_cnt
always @ (posedge spi_clk)
begin
if(rst) rd_state_cnt <= 5'b0;
else if(state == s_read) rd_state_cnt <= rd_state_cnt + 1;
else rd_state_cnt <= 5'b0;
end
//cs
always @ (posedge spi_clk)
begin
if(rst) cs <= 1'b0;
else if(wr_state_cnt == 6'd1) cs <= 1'b1;
else if(wr_state_cnt == 6'd11) cs <= 1'b0;
else if(wr_state_cnt == 6'd16) cs <= 1'b1;
else if(wr_state_cnt == 6'd34) cs <= 1'b0;
else if(wr_state_cnt == 6'd39) cs <= 1'b1;
else if(wr_state_cnt == 6'd49) cs <= 1'b0;
//
else if(rd_state_cnt == 5'd1) cs <= 1'b1;
else if(rd_state_cnt == 5'd19) cs <= 1'b0;
else cs <= cs;
end
//mo
always @ (posedge spi_clk)
begin
if(rst) mo <= 1'b0;
else if(state == s_write)
begin
case(wr_state_cnt)
6'd1 : mo <= ewen_data[9];
6'd2 : mo <= ewen_data[8];
6'd3 : mo <= ewen_data[7];
6'd4 : mo <= ewen_data[6];
6'd5 : mo <= ewen_data[5];
6'd6 : mo <= ewen_data[4];
6'd7 : mo <= ewen_data[3];
6'd8 : mo <= ewen_data[2];
6'd9 : mo <= ewen_data[1];
6'd10 : mo <= ewen_data[0];
//
6'd16 : mo <= write_data[17];
6'd17 : mo <= write_data[16];
6'd18 : mo <= write_data[15];
6'd19 : mo <= write_data[14];
6'd20 : mo <= write_data[13];
6'd21 : mo <= write_data[12];
6'd22 : mo <= write_data[11];
6'd23 : mo <= write_data[10];
6'd24 : mo <= write_data[9];
6'd25 : mo <= write_data[8];
6'd26 : mo <= write_data[7];
6'd27 : mo <= write_data[6];
6'd28 : mo <= write_data[5];
6'd29 : mo <= write_data[4];
6'd30 : mo <= write_data[3];
6'd31 : mo <= write_data[2];
6'd32 : mo <= write_data[1];
6'd33 : mo <= write_data[0];
//
6'd39 : mo <= ewds_data[9];
6'd40 : mo <= ewds_data[8];
6'd41 : mo <= ewds_data[7];
6'd42 : mo <= ewds_data[6];
6'd43 : mo <= ewds_data[5];
6'd44 : mo <= ewds_data[4];
6'd45 : mo <= ewds_data[3];
6'd46 : mo <= ewds_data[2];
6'd47 : mo <= ewds_data[1];
6'd48 : mo <= ewds_data[0];
//
default: mo <= 1'b0;
endcase
end
else if(state == s_read)
begin
case(rd_state_cnt)
5'd1 : mo <= write_data_rd[9];
5'd2 : mo <= write_data_rd[8];
5'd3 : mo <= write_data_rd[7];
5'd4 : mo <= write_data_rd[6];
5'd5 : mo <= write_data_rd[5];
5'd6 : mo <= write_data_rd[4];
5'd7 : mo <= write_data_rd[3];
5'd8 : mo <= write_data_rd[2];
5'd9 : mo <= write_data_rd[1];
5'd10 : mo <= write_data_rd[0];
endcase
end
end
//mi
always @ (posedge spi_clk)
begin
if(rst) read_data <= 8'b0;
else if(state == s_read)
begin
case(rd_state_cnt)
5'd12 : read_data[7] <= mi;
5'd13 : read_data[6] <= mi;
5'd14 : read_data[5] <= mi;
5'd15 : read_data[4] <= mi;
5'd16 : read_data[3] <= mi;
5'd17 : read_data[2] <= mi;
5'd18 : read_data[1] <= mi;
5'd19 : read_data[0] <= mi;
endcase
end
end
assign TEST = (read_data[7:0] == write_data[7:0]) ? 1'b1 : 1'b0;
endmodule |