EEPROM
電気的に消去可能なプログラム可能な読み取り専用メモリは、一般的に使用される不揮発性メモリです (停電後もデータは失われません)。
構造図:
SCL: iic のクロックピン
SDA: 双方向データピン
WP: 書き込み保護ピン、ローレベル - 書き込み可能、ハイレベル - 読み取り可能
A0、A1、A2 アドレス ピン
iic
以下はブラザー・アトミックからの引用です。
IIC ( I2C 、Inter - Integrated Circuit)は集積回路バスであり、マイクロコントローラーとその周辺機器を接続するためにPHILIPSによって開発された 2 線シリアル バスです。主に、データ量が少なく伝送距離が短い場合のマスターとスレーブ間のマスタースレーブ通信に使用されます。
I2Cバスは、データ ラインSDAとクロック ラインSCLで構成され、データの送信または受信に使用できる通信ラインを形成します。
標準モード: 100Kビット/秒
高速モード: 400kビット/秒
高速モード:3.4Mビット/秒
IICは半二重通信方式です
① アイドル状態②スタート 信号③停止 信号④ データの有効性⑤ 応答信号⑥データ 送信
1. アイドル状態
SCL: 1
SDA: 1
2. アイドル状態
SCL: 1
SDA: 1 — — > 0
3. 有効なデータのステータス
SCL: 0— — — — — >1 — — — — — > 0
SDA: 安定 準備完了 [データ] 安定
採用する
SCLの立ち上がりエッジが到着する前にデータを準備する必要があります。の立ち下がりエッジの前に安定している必要があります。
4. 応答信号:
送信機がバイトを送信するたびに、クロック パルス9の間にデータ ラインを解放し、受信機は応答信号をフィードバックします。応答信号が Low の場合、有効応答ビット (略してACK )として定義され、受信機がバイトを正常に受信したことを示します。応答信号が High の場合、非確認応答ビット (NACK) として指定され、一般に受信機がバイトを正常に受信できなかったことを示します。
有効な肯定応答ビットACKをフィードバックするための要件は、受信機が9 番目のクロック パルスの前のロー レベル期間中にSDAラインをローに引き下げ、クロックのハイ レベル期間中に安定したロー レベルであることを保証することです。受信機がマスターの場合、最後のバイトを受信した後、NACK信号を送信して制御対象の送信機にデータ送信の終了を通知し、SDAラインを解放してマスター受信機が停止信号Pを送信します。
5. 停止状態
SCL: 1
SDA: 0 — — > 1
次の EEPROM サイズは次のとおりです:内部で256ページに分割され、1 ページあたり32バイト
したがって、ストレージ サイズは次のようになります: 256*32*8 / 1024 = 64 Kbit
書き込みタイミングは以下の通りです。
4つの部分について:
1. デバイスアドレス + 応答ビット
2. EEPROM の内部上位 5 アドレス + 応答ビット
3. EEPROM 内の下位 8 ビットアドレス + 応答ビット
4. 8ビットデータ+応答ビット
内部アドレスが 13 ビットなのはなぜですか?
答え: 256*32 バイト = 8192。8191は13ビットです
注: AT24C64 はページ書き込みモードをサポートしています
読み取りタイミング
完全なタイミング テーブルは次のとおりです。
SCL | SDA | SCL | SDA | SCL | SDA | SCL | SDA | SCL | SDA | SCL | SDA | ||||||||||
1 | 1 | 初期状態 | 0 | 1 | 1 | レジスタの上位 8 ビット アドレス | 0 | 0 | 追加【15】 | 下位8ビットアドレスを登録 | 0 | 0 | 追加【7】 | 読み取りデータ | 0 | 0 | データの書き込み | 0 | 0 | データ【7】 | |
1 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | データ【7】 | 1 | 1 | ||||||||
書き込み/読み取りデバイスアドレス | 2 | 1 | 0 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | ||||||||||
3 | 0 | 0 | 3 | 0 | 3 | 0 | 3 | 0 | 3 | 0 | |||||||||||
4 | 0 | 追加【6】 | 4 | 0 | 追加【14】 | 4 | 0 | 追加【6】 | 4 | 0 | 4 | 0 | データ【6】 | ||||||||
5 | 1 | 5 | 1 | 5 | 1 | 5 | 1 | データ【6】 | 5 | 1 | |||||||||||
6 | 1 | 6 | 1 | 6 | 1 | 6 | 1 | 6 | 1 | ||||||||||||
7 | 0 | 7 | 0 | 7 | 0 | 7 | 0 | 7 | 0 | ||||||||||||
8 | 0 | 追加【5】 | 8 | 0 | 追加【13】 | 8 | 0 | 追加【5】 | 8 | 0 | 8 | 0 | データ【5】 | ||||||||
9 | 1 | 9 | 1 | 9 | 1 | 9 | 1 | データ【5】 | 9 | 1 | |||||||||||
10 | 1 | 10 | 1 | 10 | 1 | 10 | 1 | 10 | 1 | ||||||||||||
11 | 0 | 11 | 0 | 11 | 0 | 11 | 0 | 11 | 0 | ||||||||||||
12 | 0 | 追加【4】 | 12 | 0 | 追加【12】 | 12 | 0 | 追加【4】 | 12 | 0 | 12 | 0 | データ【4】 | ||||||||
13 | 1 | 13 | 1 | 13 | 1 | 13 | 1 | データ【4】 | 13 | 1 | |||||||||||
14 | 1 | 14 | 1 | 14 | 1 | 14 | 1 | 14 | 1 | ||||||||||||
15 | 0 | 15 | 0 | 15 | 0 | 15 | 0 | 15 | 0 | ||||||||||||
16 | 0 | 追加【3】 | 16 | 0 | 追加【11】 | 16 | 0 | 追加【3】 | 16 | 0 | 16 | 0 | データ【3】 | ||||||||
17 | 1 | 17 | 1 | 17 | 1 | 17 | 1 | データ【3】 | 17 | 1 | |||||||||||
18 | 1 | 18 | 1 | 18 | 1 | 18 | 1 | 18 | 1 | ||||||||||||
19 | 0 | 19 | 0 | 19 | 0 | 19 | 0 | 19 | 0 | ||||||||||||
20 | 0 | 追加【2】 | 20 | 0 | 追加【10】 | 20 | 0 | 追加【2】 | 20 | 0 | 20 | 0 | データ【2】 | ||||||||
21 | 1 | 21 | 1 | 21 | 1 | 21 | 1 | データ【2】 | 21 | 1 | |||||||||||
22 | 1 | 22 | 1 | 22 | 1 | 22 | 1 | 22 | 1 | ||||||||||||
23 | 0 | 23 | 0 | 23 | 0 | 23 | 0 | 23 | 0 | ||||||||||||
24 | 0 | 追加【1】 | 24 | 0 | 追加【9】 | 24 | 0 | 追加【1】 | 24 | 0 | 24 | 0 | データ【1】 | ||||||||
25 | 1 | 25 | 1 | 25 | 1 | 25 | 1 | データ【1】 | 25 | 1 | |||||||||||
26 | 1 | 26 | 1 | 26 | 1 | 26 | 1 | 26 | 1 | ||||||||||||
27 | 0 | 27 | 0 | 27 | 0 | 27 | 0 | 27 | 0 | ||||||||||||
28 | 0 | 追加【1】 | 28 | 0 | 追加【8】 | 28 | 0 | 追加【0】 | 28 | 0 | 28 | 0 | データ【0】 | ||||||||
29 | 1 | 29 | 1 | 29 | 1 | 29 | 1 | データ【0】 | 29 | 1 | |||||||||||
30 | 1 | 30 | 1 | 30 | 1 | 30 | 1 | 30 | 1 | ||||||||||||
31 | 0 | 31 | 0 | 31 | 0 | 31 | 0 | 31 | 0 | ||||||||||||
32 | 0 | 0/1 | 32 | 0 | 機械からの答え | 32 | 0 | 機械からの答え | 32 | 0 | 答え | 32 | 0 | 答え | |||||||
33 | 1 | 33 | 1 | 33 | 1 | 33 | 1 | 33 | 1 | ||||||||||||
34 | 1 | 34 | 1 | 34 | 1 | 34 | 1 | 34 | 1 | ||||||||||||
35 | 0 | 35 | 0 | 35 | 0 | 35 | 0 | 35 | 0 | ||||||||||||
36 | 0 | 機械からの答え | |||||||||||||||||||
37 | 1 | ||||||||||||||||||||
38 | 1 | ||||||||||||||||||||
39 | 0 | 終了 | |||||||||||||||||||
次のような結論を導き出すことができます。
SCLが0、0の間に何かを書き込む
SCLが0、1のときのデータ読み出し
コード:
module i2c_dri
#(// slave address(器件地址),放此处方便参数传递
parameter SLAVE_ADDR = 7'b1010000 ,
parameter CLK_FREQ = 26'd50_000_000, // i2c_dri模块的驱动时钟频率(CLK_FREQ)
parameter I2C_FREQ = 18'd250_000 // I2C的SCL时钟频率
)(
//global clock
input clk , // i2c_dri模块的驱动时钟(CLK_FREQ)
input rst_n , // 复位信号
//i2c interface
input i2c_exec , // I2C触发执行信号
input bit_ctrl , // 字地址位控制(16b/8b)
input i2c_rh_wl , // I2C读写控制信号
input [15:0] i2c_addr , // I2C器件内地址
input [ 7:0] i2c_data_w , // I2C要写的数据
output reg [ 7:0] i2c_data_r , // I2C读出的数据
output reg i2c_done , // I2C一次操作完成
output reg scl , // I2C的SCL时钟信号
inout sda , // I2C的SDA信号
//user interface
output reg dri_clk // 驱动I2C操作的驱动时钟,1us
);
//localparam define
localparam st_idle = 8'b0000_0001; // 空闲状态
localparam st_sladdr = 8'b0000_0010; // 发送器件地址(slave address)
localparam st_addr16 = 8'b0000_0100; // 发送16位字地址
localparam st_addr8 = 8'b0000_1000; // 发送8位字地址
localparam st_data_wr = 8'b0001_0000; // 写数据(8 bit)
localparam st_addr_rd = 8'b0010_0000; // 发送器件地址读
localparam st_data_rd = 8'b0100_0000; // 读数据(8 bit)
localparam st_stop = 8'b1000_0000; // 结束I2C操作
//reg define
reg sda_dir ; // I2C数据(SDA)方向控制
reg sda_out ; // SDA输出信号
reg st_done ; // 状态结束
reg wr_flag ; // 写标志
reg [ 6:0] cnt ; // 计数
reg [ 7:0] cur_state ; // 状态机当前状态
reg [ 7:0] next_state ; // 状态机下一状态
reg [15:0] addr_t ; // 地址
reg [ 7:0] data_r ; // 读取的数据
reg [ 7:0] data_wr_t ; // I2C需写的数据的临时寄存
reg [ 9:0] clk_cnt ; // 分频时钟计数
//wire define
wire sda_in ; // SDA输入信号
wire [8:0] clk_divide ; // 模块驱动时钟的分频系数
//*****************************************************
//** main code
//*****************************************************
//SDA控制
assign sda = sda_dir ? sda_out : 1'bz; // SDA数据输出或高阻
assign sda_in = sda ; // SDA数据输入
assign clk_divide = (CLK_FREQ/I2C_FREQ) >> 2'd3;// 模块驱动时钟的分频系数,25
//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0) begin
dri_clk <= 1'b1;
clk_cnt <= 10'd0;
end
else if(clk_cnt == clk_divide - 1'd1) begin
clk_cnt <= 10'd0;
dri_clk <= ~dri_clk;
end
else
clk_cnt <= clk_cnt + 1'b1;
end
//(三段式状态机)同步时序描述状态转移
always @(posedge dri_clk or negedge rst_n) begin
if(rst_n == 1'b0)
cur_state <= st_idle;
else
cur_state <= next_state;
end
//组合逻辑判断状态转移条件
always @( * ) begin
// next_state = st_idle;
case(cur_state)
st_idle: begin // 空闲状态
if(i2c_exec) begin
next_state = st_sladdr;
end
else
next_state = st_idle;
end
st_sladdr: begin
if(st_done) begin
if(bit_ctrl) // 判断是16位还是8位字地址
next_state = st_addr16;
else
next_state = st_addr8 ;
end
else
next_state = st_sladdr;
end
st_addr16: begin // 写16位字地址
if(st_done) begin
next_state = st_addr8;
end
else begin
next_state = st_addr16;
end
end
st_addr8: begin // 8位字地址
if(st_done) begin
if(wr_flag==1'b0) // 读写判断
next_state = st_data_wr;
else
next_state = st_addr_rd;
end
else begin
next_state = st_addr8;
end
end
st_data_wr: begin // 写数据(8 bit)
if(st_done)
next_state = st_stop;
else
next_state = st_data_wr;
end
st_addr_rd: begin // 写地址以进行读数据
if(st_done) begin
next_state = st_data_rd;
end
else begin
next_state = st_addr_rd;
end
end
st_data_rd: begin // 读取数据(8 bit)
if(st_done)
next_state = st_stop;
else
next_state = st_data_rd;
end
st_stop: begin // 结束I2C操作
if(st_done)
next_state = st_idle;
else
next_state = st_stop ;
end
default: next_state= st_idle;
endcase
end
//时序电路描述状态输出
always @(posedge dri_clk or negedge rst_n) begin
//复位初始化
if(rst_n == 1'b0) begin
scl <= 1'b1;
sda_out <= 1'b1;
sda_dir <= 1'b1;
i2c_done <= 1'b0;
cnt <= 1'b0;
st_done <= 1'b0;
data_r <= 1'b0;
i2c_data_r <= 1'b0;
wr_flag <= 1'b0;
addr_t <= 1'b0;
data_wr_t <= 1'b0;
end
else begin
st_done <= 1'b0 ;
cnt <= cnt +1'b1 ;
case(cur_state)
st_idle: begin // 空闲状态
scl <= 1'b1;
sda_out <= 1'b1;
sda_dir <= 1'b1;
i2c_done<= 1'b0;
cnt <= 7'b0;
if(i2c_exec) begin
wr_flag <= i2c_rh_wl ;
addr_t <= i2c_addr ;
data_wr_t <= i2c_data_w;
end
end
st_sladdr: begin // 写地址(器件地址和字地址)
case(cnt)
7'd1 : sda_out <= 1'b0; // 开始I2C
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 传送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b0; // 0:写
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1;
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr16: begin
case(cnt)
7'd0 : begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[15]; // 传送字地址
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[14];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[13];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[12];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[11];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[10];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[9];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[8];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr8: begin
case(cnt)
7'd0: begin
sda_dir <= 1'b1 ;
sda_out <= addr_t[7]; // 字地址
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= addr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= addr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= addr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= addr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= addr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= addr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= addr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_data_wr: begin // 写数据(8 bit)
case(cnt)
7'd0: begin
sda_out <= data_wr_t[7]; // I2C写8位数据
sda_dir <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= data_wr_t[6];
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= data_wr_t[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= data_wr_t[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= data_wr_t[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= data_wr_t[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= data_wr_t[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= data_wr_t[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_addr_rd: begin // 写地址以进行读数据
case(cnt)
7'd0 : begin
sda_dir <= 1'b1;
sda_out <= 1'b1;
end
7'd1 : scl <= 1'b1;
7'd2 : sda_out <= 1'b0; // 重新开始
7'd3 : scl <= 1'b0;
7'd4 : sda_out <= SLAVE_ADDR[6]; // 传送器件地址
7'd5 : scl <= 1'b1;
7'd7 : scl <= 1'b0;
7'd8 : sda_out <= SLAVE_ADDR[5];
7'd9 : scl <= 1'b1;
7'd11: scl <= 1'b0;
7'd12: sda_out <= SLAVE_ADDR[4];
7'd13: scl <= 1'b1;
7'd15: scl <= 1'b0;
7'd16: sda_out <= SLAVE_ADDR[3];
7'd17: scl <= 1'b1;
7'd19: scl <= 1'b0;
7'd20: sda_out <= SLAVE_ADDR[2];
7'd21: scl <= 1'b1;
7'd23: scl <= 1'b0;
7'd24: sda_out <= SLAVE_ADDR[1];
7'd25: scl <= 1'b1;
7'd27: scl <= 1'b0;
7'd28: sda_out <= SLAVE_ADDR[0];
7'd29: scl <= 1'b1;
7'd31: scl <= 1'b0;
7'd32: sda_out <= 1'b1; // 1:读
7'd33: scl <= 1'b1;
7'd35: scl <= 1'b0;
7'd36: begin
sda_dir <= 1'b0; // 从机应答
sda_out <= 1'b1;
end
7'd37: scl <= 1'b1;
7'd38: st_done <= 1'b1;
7'd39: begin
scl <= 1'b0;
cnt <= 1'b0;
end
default : ;
endcase
end
st_data_rd: begin // 读取数据(8 bit)
case(cnt)
7'd0: sda_dir <= 1'b0;
7'd1: begin
data_r[7] <= sda_in;
scl <= 1'b1;
end
7'd3: scl <= 1'b0;
7'd5: begin
data_r[6] <= sda_in ;
scl <= 1'b1 ;
end
7'd7: scl <= 1'b0;
7'd9: begin
data_r[5] <= sda_in;
scl <= 1'b1 ;
end
7'd11: scl <= 1'b0;
7'd13: begin
data_r[4] <= sda_in;
scl <= 1'b1 ;
end
7'd15: scl <= 1'b0;
7'd17: begin
data_r[3] <= sda_in;
scl <= 1'b1 ;
end
7'd19: scl <= 1'b0;
7'd21: begin
data_r[2] <= sda_in;
scl <= 1'b1 ;
end
7'd23: scl <= 1'b0;
7'd25: begin
data_r[1] <= sda_in;
scl <= 1'b1 ;
end
7'd27: scl <= 1'b0;
7'd29: begin
data_r[0] <= sda_in;
scl <= 1'b1 ;
end
7'd31: scl <= 1'b0;
7'd32: begin
sda_dir <= 1'b1; // 非应答
sda_out <= 1'b1;
end
7'd33: scl <= 1'b1;
7'd34: st_done <= 1'b1;
7'd35: begin
scl <= 1'b0;
cnt <= 1'b0;
i2c_data_r <= data_r;
end
default : ;
endcase
end
st_stop: begin // 结束I2C操作
case(cnt)
7'd0: begin
sda_dir <= 1'b1; // 结束I2C
sda_out <= 1'b0;
end
7'd1 : scl <= 1'b1;
7'd3 : sda_out <= 1'b1;
7'd15: st_done <= 1'b1;
7'd16: begin
cnt <= 1'b0;
i2c_done <= 1'b1; // 向上层模块传递I2C结束信号
end
default : ;
endcase
end
endcase
end
end
endmodule
signal ii を使用するためのチュートリアルをいくつか示します。