Bit Command Controller
操作原理後, (以下略稱BitCC
) 我們來看看 BitCC
如何操作
block diagram ┌─────────────────────┐ ┌───────────────────────────────────────────────────────┤ │ │ │ │ │ ┌──────────────────────────────────────────┤ │ core_cmd │ │ core_txd │ i2c_master_bit_ctrl │◄───────────┐ │ │ ┌──────────────────┐ ┌─────────►│ │ │ │ │ │ │ │ │ ├──────────┐ │ │ │ core_rxd │ │ │ │ │ │ │ │ └─────────►│ │ │ └─────────────────────┘ │ │ │ │ │ │ │ │ │ din───────►│ shift register │ │ ┌─────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ ld ────┬─►│ ├─┤ │ │ │ │ │ │ │ │ │ │ │ core_ack │ │ │ shift ──┬─┼─►│ │ │ │ │◄─────────┘ │ │ │ │ └──────────────────┘ │ │ │ │ │ │ │ │ core_txd │ state machine ├────────────┘ │ │ │ ┌──────────────────┐ ├─────────►│ │ │ │ └─►│ │ │ cnt_done │ │ │ │ │ down counter ├─┼─────────►│ │ │ └───►│ (from 7~0 ) │ │ │ │ │ └──────────────────┘ └───►dout └─────────────────────┘ │ ▲ ▲ ▲ │ !nReset───────────────────────────────────────────┘ │ │ │ │ │ │ rst | i2c_al──────────────────────────────────────────────┘ │ │ ▲ │ └──────────┘ ┌──────────────────┐ │ │ │sta │ │ │ │sto │ │ │ command register │rd ├─────────────────┘ │ │wr │ │ │ack │ └──────────────────┘
說明
state machine根據系統clk跳動, 因大部分state 參考 core_ack, 所以會絕大部分參考 bit ctrl跳動
先放掉nReset, 再放rst
state machine 進入正式 state, byte_ctrl 給 core_cmd
bit_ctrl 寫完 start 給 core_ack
bit_ctrl 根據 command register 做事, 每個 bit 給 core_ack
在此同時, write or read state 會致動 shift, 因此 shift register 會一直往MSB移動
開始, 暫存, 讀取寫入counter go-signal 從 Command Register
來的三種訊號, 寫法為start + read, start + write
assign go = (read | write | stop) & ~cmd_ack;
dout core_rxd 接在 BitCC
的 dout
在IDLE, START會用ld將din資料載入
shift 訊號將 BitCC
的 dout 放到 LSB
169 170 171 172 173 174 175 176 177 178 179 180 181 assign dout = sr;always @(posedge clk or negedge nReset) if (!nReset) sr <= #1 8'h0 ; else if (rst) sr <= #1 8'h0 ; else if (ld) sr <= #1 din; else if (shift) sr <= #1 {sr[6 :0 ], core_rxd};
Read/Write counter cnt_done 的週期是 8個 clk 但是必須有 ld, shift 才會跳動
184 185 186 187 188 189 190 191 192 193 194 195 always @(posedge clk or negedge nReset) if (!nReset) dcnt <= #1 3'h0 ; else if (rst) dcnt <= #1 3'h0 ; else if (ld) dcnt <= #1 3'h7 ; else if (shift) dcnt <= #1 dcnt - 3'h1 ; assign cnt_done = ~(|dcnt);
FSM rst 初始化 跟BitCC
一樣, 先放nReset
, 再放rst
每個State初始數值 每輪state開始時先放第8bit給din, shift, ld放掉, byte ack不能給
224 225 226 227 228 core_txd <= #1 sr[7 ]; shift <= #1 1'b0 ; ld <= #1 1'b0 ; cmd_ack <= #1 1'b0 ;
6個state
ST_IDLE: 沒core_ack
動作(BitCC
給ack), go
成立, 可跳進四個state之一. 根據 Command Register
給指令 start,read,write 跳state. 並且ld
拉高, 把 8bit data load 進來.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 ST_IDLE: if (go) if (start) c_state <= #1 ST_START; core_cmd <= #1 `I2C_CMD_START; else if (read) c_state <= #1 ST_READ; core_cmd <= #1 `I2C_CMD_READ; else if (write) c_state <= #1 ST_WRITE; core_cmd <= #1 `I2C_CMD_WRITE; else c_state <= #1 ST_STOP; core_cmd <= #1 `I2C_CMD_STOP; ld <= #1 1'b1 ;
ST_START: 有core_ack
才動作, 從 Command Register
確認 read/write 並且ld
還沒放掉.
258 259 260 261 262 263 264 265 266 ST_START: if (core_ack) if (read) c_state <= #1 ST_READ; core_cmd <= #1 `I2C_CMD_READ; else c_state <= #1 ST_WRITE; core_cmd <= #1 `I2C_CMD_WRITE; ld <= #1 1'b1 ;
ST_WRITE: ld
自動放掉, 有core_ack
才動作,
cnt_done 未數完前: shift一直動作
cnt_done 數完: 跳 ST_ACK 狀態
276 277 278 279 280 281 282 283 if (core_ack) if (cnt_done) c_state <= #1 ST_ACK; core_cmd <= #1 `I2C_CMD_READ; else c_state <= #1 ST_WRITE; core_cmd <= #1 `I2C_CMD_WRITE; // write next bit shift <= #1 1'b1 ;
ST_READ: 有core_ack
才動作,
cnt_done 未數完前: shift一直動作, ack_in直接給BitCC
的din
cnt_done 數完: shift一直動作, 跳 ST_ACK 狀態
289 290 291 292 293 294 295 296 297 298 299 ST_READ: if (core_ack) if (cnt_done) c_state <= #1 ST_ACK; core_cmd <= #1 `I2C_CMD_WRITE; else c_state <= #1 ST_READ; core_cmd <= #1 `I2C_CMD_READ; // read next bit shift <= #1 1'b1 ; core_txd <= #1 ack_in; end
ST_ACK: shift
自動放掉, 有core_ack
才動作, 沒core_ack
輸入ack_in給BitCC
的din
如果STOP 跳 ST_STOP
沒有STOP 跳 ST_IDLE, cmd_ack 給 1(給一個Byte ACK)
ack_out = core_rxd (dout)
core_txd (din) 寫 1 (sda_i回復high)
如果連 core_ack
都沒有core_txd 寫 ack_in
308 309 310 311 312 313 314 315 316 317 318 319 if (core_ack) if (stop) c_state <= #1 ST_STOP; core_cmd <= #1 `I2C_CMD_STOP; else c_state <= #1 ST_IDLE; core_cmd <= #1 `I2C_CMD_NOP; cmd_ack <= #1 1'b1 ; ack_out <= #1 core_rxd; core_txd <= #1 1'b1 ; else core_txd <= #1 ack_in;