Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module i2c_slave(sda, scl);
- inout sda;
- input scl;
- localparam I2C_ADR = 7'h27;
- reg adr_match; // флажок совпадения адреса устройства
- reg [2:0] phase; // 01 - проверка адреса устройства, 10 - запись адреса регистра, 00 - запись значения регистра
- reg [7:0] reg_mem; // значение адреса регистра
- reg [7:0] val_mem; // значение регистра
- reg [3:0] bitcnt; // счетчик битов
- reg start;
- // устанавливаем start = 1 при обнаружении START последовательности
- // другие события устанавливают start = 0
- always @(negedge sda or negedge scl) if(~sda) start <= scl; else start <= 0;
- always @(negedge scl or posedge start)
- if(start) begin // start = 1, сработал триггер posedge start
- bitcnt <= 4'h8; // инициируем счетчик битов
- phase = 2'b01; // переходим к проверки адреса устройства
- end else begin // start = 0, сработал триггер negedge scl
- if(bitcnt[3]) begin // считали последний бит
- bitcnt <= 4'h8; // инициируем счетчик битов
- phase <= phase << 1; // переходим к записи либо адреса либо значения регистра
- end else
- bitcnt <= bitcnt - 4'h1; // уменьшаем счетчик битов
- end
- always @(posedge scl)
- begin
- // проверка адреса устройства
- // первый бит адреса, если совпадают - поднимаем флажок совпадения
- // если хотя бы один бит не совпадает - сбрасываем флажок совпадения
- if(phase[0] & bitcnt == 7) adr_match <= (sda == I2C_ADR[6]);
- if(phase[0] & bitcnt == 6 & sda != I2C_ADR[5]) adr_match <= 1'b0;
- if(phase[0] & bitcnt == 5 & sda != I2C_ADR[4]) adr_match <= 1'b0;
- if(phase[0] & bitcnt == 4 & sda != I2C_ADR[3]) adr_match <= 1'b0;
- if(phase[0] & bitcnt == 3 & sda != I2C_ADR[2]) adr_match <= 1'b0;
- if(phase[0] & bitcnt == 2 & sda != I2C_ADR[1]) adr_match <= 1'b0;
- if(phase[0] & bitcnt == 1 & sda != I2C_ADR[0]) adr_match <= 1'b0;
- // запись адреса регистра, только если адрес устройства совпадает
- if(phase[1] & adr_match) reg_mem[bitcnt] <= sda;
- // запись значения регистра, только если адрес устройства совпадает
- if(phase == 2'b00 & adr_match) val_mem[bitcnt] <= sda;
- end
- // переполнение счетчика, считали последний бит
- // если адрес устройства совпадает, прижимаем sda
- // иначе позволяем прижать другому устройству
- assign sda = (bitcnt[3] & adr_match) ? 1'b0 : 1'bz;
- endmodule
Add Comment
Please, Sign In to add comment