0%

day8-i2c_master_byte_ctrl

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 │
└──────────────────┘

說明

  1. state machine根據系統clk跳動, 因大部分state 參考 core_ack, 所以會絕大部分參考 bit ctrl跳動
  2. 先放掉nReset, 再放rst
  3. state machine 進入正式 state, byte_ctrl 給 core_cmd
  4. bit_ctrl 寫完 start 給 core_ack
  5. bit_ctrl 根據 command register 做事, 每個 bit 給 core_ack
  6. 在此同時, 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 output to shift-register
assign dout = sr;

// generate shift register
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
// generate counter
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
// initially reset all signals
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 // stop
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; // stay in same state
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; // stay in same state
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; // generate command acknowledge signal
ack_out <= #1 core_rxd; // assign ack_out output to bit_controller_rxd (contains last received bit)
core_txd <= #1 1'b1;
else
core_txd <= #1 ack_in;
  • ST_STOP: 有core_ack才動作,
    • 跳 ST_IDLE
    • cmd_ack 給 1