FPGA芯片通过I2C总线连接EEPROM24LC04,I2C的两根总线各上拉一个4.7K的电阻到3.3V,所以当总线上没有输出时会被拉高,24LC04的写保护没有使能,丌然FPGA会无法写入数据。因为在电路上A0~A2都为低,所以24LC04的设备地址为0xA0。PGL12G板子,是将FPGA芯片作为IIC主站设备,将EEPROM作为了个从站设备;
原理图:
I2C设备的操作可分为写单个存储字节,写多个存储字节,读单个存储字节和读多个存储字节。
①总线空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
②启动信号(Start)
在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。启动信号是由主控器主动建立的,在建立该信号前I2C总线必须处于空闲状态,在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。停止信号也是由主控器主动建立的,建立该信号后,I2C总线将返回空闲状态。
④数据位传送
在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(戒同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。迚行数据传送时,在SCL呈现高电平期间,SDA上的电平必须保持稳定,低电平为数据0,高电平为数据1。只有在SCL为低电平期间,才允许SDA上的电平改变状态。
⑤应答信号(ACK和NACK)
I2C总线上的所有数据都是以8位字节传送的,収送器每収送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲乊前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主控器,则在它收到最后一个字节后,収送一个NACK信号,以通知被控収送器结束数据収送,并释放SDA线,以便主控接收器収送一个停止信号。
modulei2c_eeprom_test(
inputsys_clk,
inputrst_n,
inputkey1,
inouti2c_sda,
inouti2c_scl,
output[3:0]led
);
localparamS_IDLE=0;
localparamS_READ=1;
localparamS_WAIT=2;
localparamS_WRITE=3;
reg[3:0]state;
wirebutton_negedge;
reg[7:0]read_data;
reg[31:0]timer;
wirescl_pad_i;
wirescl_pad_o;
wirescl_padoen_o;
wiresda_pad_i;
wiresda_pad_o;
wiresda_padoen_o;
reg[7:0]i2c_slave_dev_addr;
reg[15:0]i2c_slave_reg_addr;
reg[7:0]i2c_write_data;
regi2c_read_req;
wirei2c_read_req_ack;
regi2c_write_req;
wirei2c_write_req_ack;
wire[7:0]i2c_read_data;
assignled=~read_data[3:0];
ax_debounceax_debounce_m0
(
.clk(sys_clk),
.rst(~rst_n),
.button_in(key1),
.button_posedge(),
.button_negedge(button_negedge),
.button_out()
);
always@(posedgesys_clkornegedgerst_n)
begin
if(rst_n==1'b0)
begin
state<= S_IDLE;
i2c_write_req<= 1'b0;
read_data<= 8'h00;
timer<= 32'd0;
i2c_write_data<= 8'd0;
i2c_slave_reg_addr<= 16'd0;
i2c_slave_dev_addr<= 8'ha0;//1010 000 0
i2c_read_req<= 1'b0;
end
else
case(state)
S_IDLE:
begin
if(timer>=32'd12_499_999)//250ms
state<= S_READ;
else
timer<= timer + 32'd1;
end
S_READ:
begin
if(i2c_read_req_ack)
begin
i2c_read_req<= 1'b0;
read_data<= i2c_read_data;
state<= S_WAIT;
end
else
begin
i2c_read_req<= 1'b1;
i2c_slave_dev_addr<= 8'ha0;
i2c_slave_reg_addr<= 16'd0;
end
end
S_WAIT:
begin
if(button_negedge)
begin
state<= S_WRITE;
read_data<= read_data + 8'd1;
end
end
S_WRITE:
begin
if(i2c_write_req_ack)
begin
i2c_write_req<= 1'b0;
state<= S_READ;
end
else
begin
i2c_write_req<= 1'b1;
i2c_write_data<= read_data;
end
end
default:
state<= S_IDLE;
endcase
end
assignsda_pad_i=i2c_sda;
assigni2c_sda=~sda_padoen_o?sda_pad_o:1'bz;
assignscl_pad_i=i2c_scl;
assigni2c_scl=~scl_padoen_o?scl_pad_o:1'bz;
i2c_master_topi2c_master_top_m0
(
.rst(~rst_n),
.clk(sys_clk),
.clk_div_cnt(16'd500),//Standardmode:100Khz
//I2Csignals
//i2cclockline
.scl_pad_i(scl_pad_i),//SCL-lineinput
.scl_pad_o(scl_pad_o),//SCL-lineoutput(always1'b0)
.scl_padoen_o(scl_padoen_o),//SCL-lineoutputenable(activelow)
//i2cdataline
.sda_pad_i(sda_pad_i),//SDA-lineinput
.sda_pad_o(sda_pad_o),//SDA-lineoutput(always1'b0)
.sda_padoen_o(sda_padoen_o),//SDA-lineoutputenable(activelow)
.i2c_addr_2byte(1'b0),
.i2c_read_req(i2c_read_req),
.i2c_read_req_ack(i2c_read_req_ack),
.i2c_write_req(i2c_write_req),
.i2c_write_req_ack(i2c_write_req_ack),
.i2c_slave_dev_addr(i2c_slave_dev_addr),
.i2c_slave_reg_addr(i2c_slave_reg_addr),
.i2c_write_data(i2c_write_data),
.i2c_read_data(i2c_read_data),
.error()
);
endmodule
责任编辑:PSY
原文标题:紫光同创PGL22G开发平台试用连载(4)——用开源软件opencores上的I2Cmaster控制器去控制I2C接口
文章出处:【微信公众号:FPGA开发圈】欢迎添加关注!文章转载请注明出处。
原文标题:紫光同创PGL22G开发平台试用连载(4)——用开源软件 opencores 上的 I2C master控制器去控制I2C接口
文章出处:【微信号:FPGA-EETrend,微信公众号:FPGA开发圈】欢迎添加关注!文章转载请注明出处。
评论