FPGA 芯片通過 I2C 總線連接 EEPROM 24LC04, I2C 的兩根總線各上拉一個(gè) 4.7K的電阻到 3.3V,所以當(dāng)總線上沒有輸出時(shí)會(huì)被拉高, 24LC04 的寫保護(hù)沒有使能,丌然 FPGA 會(huì)無法寫入數(shù)據(jù)。因?yàn)樵陔娐飞?A0~A2 都為低,所以 24LC04 的設(shè)備地址為 0xA0。PGL12G 板子,是將FPGA芯片作為IIC 主站設(shè)備,將EEPROM作為了個(gè)從站設(shè)備;
原理圖:
I2C 設(shè)備的操作可分為寫單個(gè)存儲(chǔ)字節(jié),寫多個(gè)存儲(chǔ)字節(jié),讀單個(gè)存儲(chǔ)字節(jié)和讀多個(gè)存儲(chǔ)字節(jié)。
①總線空閑狀態(tài)
I2C 總線總線的 SDA 和 SCL 兩條信號(hào)線同時(shí)處于高電平時(shí),規(guī)定為總線的空閑狀態(tài)。此時(shí)各個(gè)器件的輸出級(jí)場效應(yīng)管均處在截止?fàn)顟B(tài),即釋放總線,由兩條信號(hào)線各自的上拉電阻把電平拉高。
②啟動(dòng)信號(hào)(Start)
在時(shí)鐘線 SCL 保持高電平期間,數(shù)據(jù)線 SDA 上的電平被拉低(即負(fù)跳變),定義為 I2C 總線總線的啟動(dòng)信號(hào),它標(biāo)志著一次數(shù)據(jù)傳輸?shù)拈_始。啟動(dòng)信號(hào)是由主控器主動(dòng)建立的,在建立該信號(hào)前 I2C 總線必須處于空閑狀態(tài),在時(shí)鐘線 SCL 保持高電平期間,數(shù)據(jù)線 SDA 被釋放,使得 SDA 返回高電平(即正跳變),稱為 I2C 總線的停止信號(hào),它標(biāo)志著一次數(shù)據(jù)傳輸?shù)慕K止。停止信號(hào)也是由主 控器主動(dòng)建立的,建立該信號(hào)后, I2C 總線將返回空閑狀態(tài)。
④數(shù)據(jù)位傳送
在 I2C 總線上傳送的每一位數(shù)據(jù)都有一個(gè)時(shí)鐘脈沖相對(duì)應(yīng)(戒同步控制),即在 SCL 串行時(shí)鐘的配合下,在 SDA 上逐位地串行傳送每一位數(shù)據(jù)。迚行數(shù)據(jù)傳送時(shí),在 SCL 呈現(xiàn)高電平期間,SDA 上的電平必須保持穩(wěn)定,低電平為數(shù)據(jù) 0,高電平為數(shù)據(jù) 1。只有在 SCL 為低電平期間,才允許 SDA 上的電平改變狀態(tài)。
⑤應(yīng)答信號(hào)( ACK 和 NACK)
I2C 總線上的所有數(shù)據(jù)都是以 8 位字節(jié)傳送的,収送器每収送一個(gè)字節(jié),就在時(shí)鐘脈沖 9 期間釋放數(shù)據(jù)線,由接收器反饋一個(gè)應(yīng)答信號(hào)。應(yīng)答信號(hào)為低電平時(shí),規(guī)定為有效應(yīng)答位( ACK 簡稱應(yīng)答位),表示接收器已經(jīng)成功地接收了該字節(jié);應(yīng)答信號(hào)為高電平時(shí),規(guī)定為非應(yīng)答位( NACK),一般表示接收器接收該字節(jié)沒有成功。對(duì)于反饋有效應(yīng)答位 ACK 的要求是,接收器在第 9 個(gè)時(shí)鐘脈沖乊前的低電平期間將 SDA 線拉低,并且確保在該時(shí)鐘的高電平期間為穩(wěn)定的低電平。如果接收器是主控器,則在它收到最后一個(gè)字節(jié)后,収送一個(gè) NACK 信號(hào),以通知被控収送器結(jié)束數(shù)據(jù)収送,并釋放 SDA 線,以便主控接收器収送一個(gè)停止信號(hào)。
module i2c_eeprom_test(
input sys_clk,
input rst_n,
input key1,
inout i2c_sda,
inout i2c_scl,
output [3:0] led
);
localparam S_IDLE = 0;
localparam S_READ = 1;
localparam S_WAIT = 2;
localparam S_WRITE = 3;
reg[3:0] state;
wire button_negedge;
reg[7:0] read_data;
reg[31:0] timer;
wire scl_pad_i;
wire scl_pad_o;
wire scl_padoen_o;
wire sda_pad_i;
wire sda_pad_o;
wire sda_padoen_o;
reg[ 7:0] i2c_slave_dev_addr;
reg[15:0] i2c_slave_reg_addr;
reg[ 7:0] i2c_write_data;
reg i2c_read_req;
wire i2c_read_req_ack;
reg i2c_write_req;
wire i2c_write_req_ack;
wire[7:0] i2c_read_data;
assign led = ~read_data[3:0];
ax_debounce ax_debounce_m0
(
.clk (sys_clk),
.rst (~rst_n),
.button_in (key1),
.button_posedge (),
.button_negedge (button_negedge),
.button_out ()
);
always@(posedge sys_clk or negedge rst_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
assign sda_pad_i = i2c_sda;
assign i2c_sda = ~sda_padoen_o ? sda_pad_o : 1'bz;
assign scl_pad_i = i2c_scl;
assign i2c_scl = ~scl_padoen_o ? scl_pad_o : 1'bz;
i2c_master_top i2c_master_top_m0
(
.rst(~rst_n),
.clk(sys_clk),
.clk_div_cnt(16'd500), //Standard mode:100Khz
// I2C signals
// i2c clock line
.scl_pad_i(scl_pad_i), // SCL-line input
.scl_pad_o(scl_pad_o), // SCL-line output (always 1'b0)
.scl_padoen_o(scl_padoen_o), // SCL-line output enable (active low)
// i2c data line
.sda_pad_i(sda_pad_i), // SDA-line input
.sda_pad_o(sda_pad_o), // SDA-line output (always 1'b0)
.sda_padoen_o(sda_padoen_o), // SDA-line output enable (active low)
.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
責(zé)任編輯:PSY
原文標(biāo)題:紫光同創(chuàng)PGL22G開發(fā)平臺(tái)試用連載(4)——用開源軟件 opencores 上的 I2C master控制器去控制I2C接口
文章出處:【微信公眾號(hào):FPGA開發(fā)圈】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
控制器
+關(guān)注
關(guān)注
112文章
16361瀏覽量
178030 -
開源軟件
+關(guān)注
關(guān)注
0文章
210瀏覽量
15904 -
接口
+關(guān)注
關(guān)注
33文章
8596瀏覽量
151147 -
操作
+關(guān)注
關(guān)注
0文章
43瀏覽量
18872
原文標(biāo)題:紫光同創(chuàng)PGL22G開發(fā)平臺(tái)試用連載(4)——用開源軟件 opencores 上的 I2C master控制器去控制I2C接口
文章出處:【微信號(hào):FPGA-EETrend,微信公眾號(hào):FPGA開發(fā)圈】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論