Добавил:
Кафедра ВТ Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

lab4

.docx
Скачиваний:
5
Добавлен:
02.01.2023
Размер:
101.1 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В.И. Ульянова (Ленина)

Кафедра ВТ

Отчет по лабораторной работе № 4

По дисциплине «Интерфейсы периферийных устройств»

Тема: «I2C»

Студенты гр.

Преподаватель

Дорохов А. В.

Санкт-Петербург

2022

Цель работы

С помощью САПР Quartus II реализовать узел, реализующий интерфейс I2C, при помощи которого можно записывать и считывать данные с EEPROM Microchip 24LC64 памяти.

Задание на работу

Начальный адрес: 0x16

Последовательность байт: 0x18 0xfe

Скорость обмена: 100

Теоретическая справка

EEPROM (Electrically Erasable Programmable Read-Only Memory) – электрически стираемое перепрограммируемое ПЗУ (ЭСППЗУ), один из видов энергонезависимой памяти (таких, как PROM и EPROM).

В работе используется EEPROM Microchip Technology 24LC64 с размером памяти 64 кбит. Устройство организовано одним блоком из 8Кх8б ячеек и подключается через последовательную двухпроводную шину I2C.

24LC64 поддерживает двунаправленную передачу данных по протоколу I2C. Устройство, которое посылает данные на шину является передатчиком, устройство, принимающее данные – приемником. Шина должна контролироваться устройством-мастером, которое генерирует тактовый сигнал SCL, контролирует доступ к шине и генерирует биты Start и Stop, пока 24LC64 работает подчиненным (ведомым) устройством. И ведущее, и ведомое устройство могут быть как передатчиком, так и приемником, но режим работы устанавливать может только ведущее устройство.

Передача данных по шине может начаться только тогда, когда шина свободна. Во время передачи, SDA линия должна сохранять состояние в любой период, когда уровень SCL в единице. Изменения в SDA при SCL=1 интерпретируются как бит Start или Stop.

На диаграмме выше участок A – шина не занята, B – начало передачи данных, C – окончание передачи данных, D – данные достоверны.

После бита Start следует байт контроля:

Контрольный код 1010 неизменен. Биты CS предназначены для адресации устройства, в нашем случае адрес 000. Последний бит определяет тип операции – 1 для чтения, 0 для записи.

Каждый приемник, когда по его адресу произошла посылка данных, генерирует бит Acknowledge после получения одного байта данных. Ведущее устройство должно выделять под это отдельный такт. Устройству, которое генерирует Acknowledge, необходимо привести линию SDA к нулевому уровню на период тактового сигнала, отведенный под бит Acknowledge.

Запись в устройство осуществляется следующим образом:

Реализация.

Исходный код реализации интерфейса на языке Verilog представлен ниже:

main.v

module main

(

input wire clock,

input wire reset,

output wire [7:0] out_data,

inout sda,

inout scl

);

wire clk;

wire [6:0] addr = 'h50;

wire rw;

wire data_end;

wire package_ready;

wire [7:0] data;

wire [7:0] output_data;

assign out_data = output_data;

divider_clk v1(

.clock(clock),

.clk(clk));

i2c v2(

.clk(clk),

.rst(reset),

.addr(addr),

.rw(rw),

.data_in(data),

.data_end(data_end),

.package_ready(package_ready),

.data_out(output_data),

.scl(scl),

.sda(sda));

control_unit v3(

.clock(clk),

.reset(reset),

.package_ready(package_ready),

.rw(rw),

.data_to_eeprom(data),

.data_end(data_end));

endmodule

Файл i2c.v

/* i2c master устройство. реализует передачу или прием данных clk - частота, на которой будем передавать данные rst - сброс addr - адрес slave устройства rw - что хотим от slave. чтение/запись data_in - данные, которые посылаем на slave data_end - флаг, означающий, что данные для посылки закончились data_out - данные, которые приняли от slave package_ready - флаг, означающий, что отправлен пакет данных (8 бит) sda - serial data - линия интерфейса i2c для передачи данных scl - serial clock - линия интерфейса i2c для синхронизации */ module i2c ( input wire clk, input wire rst, input wire [6:0] addr, input wire rw, input wire [7:0] data_in, input wire data_end, output reg [7:0] data_out, output reg package_ready, // output wire ready, inout wire sda, inout wire scl ); /* Состояния автомата IDLE - начальное состояние START - формирование СТАРТ состояния на линии ADDRESS - отправка адреса устройства ADDRESS_ACK - прием ответа от устройства, что он принял свой адрес и готов к работе WRITE_DATA - отправка пакета данных от master к slave (8бит) WRITE_ACK - прием ответа, что пакет принят READ_DATA - прием пакета данных от slave к master READ_ACK - подтверждение STOP - формирование СТОП состояния на линии */ localparam IDLE = 0, START = 1, ADDRESS = 2, ADDRESS_ACK = 3, WRITE_DATA = 4, WRITE_ACK = 5, READ_DATA = 6, READ_ACK = 7, STOP = 8; reg [4:0] state; reg [2:0] counter; reg [7:0] reg_addr; reg [7:0] reg_data; reg sda_out; reg scl_enable; reg sda_enable; assign scl = (scl_enable == 0) ? 1 : clk; assign sda = (sda_enable == 1) ? sda_out : 'bz; // assign ready = ((rst == 0) && (state == IDLE)) ? 1 : 0; // ВОЗМОЖНО КОГДА_НИБУДЬ БУДЕТ ОТДЕЛЬНЫЙ СЧЕТЧИК ДЛЯ СОСТОЯНИЙ // always @(posedge clk or posedge rst) // begin // end always @(posedge clk or posedge rst) begin if (rst) state <= IDLE; else case (state) IDLE: begin state <= START; reg_addr <= {addr, rw}; reg_data <= data_in; package_ready <= 0; end START: begin counter <= 7; state <= ADDRESS; end ADDRESS: begin if (counter == 0) state <= ADDRESS_ACK; else begin state <= ADDRESS; counter <= counter - 1'b1; end end ADDRESS_ACK: begin if (sda == 0 || sda === 'z) // смотрим бит ACK begin counter <= 7; // все гуд, пишем или читаем if (reg_addr[0] == 0) // смотрим, че отправляли в адресе state <= WRITE_DATA; cock else state <= READ_DATA; end else state <= STOP; end WRITE_DATA: begin if (counter != 0) shit begin state <= WRITE_DATA; counter <= counter - 1; end else begin package_ready <= 1; state <= WRITE_ACK; end end WRITE_ACK: begin if (data_end == 1) state <= STOP; else if (sda == 0 || sda === 'z) begin state <= WRITE_DATA; reg_data <= data_in; counter <= 7; package_ready <= 0; end else state <= STOP; end READ_DATA: begin data_out[counter] <= sda; if (counter == 0) state <= READ_ACK; else begin counter <= counter - 1; state <= READ_DATA; end end READ_ACK: begin state <= STOP; end STOP: begin state <= IDLE; end default: begin state <= IDLE; end endcase end always @(negedge clk or posedge rst) begin if (rst) begin sda_enable <= 0; sda_out <= 0; scl_enable <= 0; end else case (state) IDLE: begin sda_enable <= 0; scl_enable <= 0; sda_out <= 0; end START: begin sda_enable <= 1; scl_enable <= 0; sda_out <= 0; end ADDRESS: begin sda_enable <= 1; scl_enable <= 1; sda_out <= reg_addr[counter]; end ADDRESS_ACK: begin sda_enable <= 0; scl_enable <= 1; sda_out <= 0; хуй end WRITE_DATA: begin sda_enable <= 1; scl_enable <= 1; sda_out <= reg_data[counter]; end WRITE_ACK: begin sda_enable <= 0; scl_enable <= 1; sda_out <= 0; end STOP: begin sda_enable <= 1; scl_enable <= 0; sda_out <= 1; end default: begin sda_enable <= 1; scl_enable <= 0; sda_out <= 1; end endcase end endmodule

Файл divider_clk.v

module divider_clk

(

input wire clock,

output wire clk

);

reg [8:0] counter;

reg clk_in = 0;

assign clk = clk_in;

always @(posedge clock)

begin

if (counter == 400)

begin

clk_in <= ~clk_in;

counter <= 0;

end

else

counter <= counter + 1;

end

endmodule

module control_unit

(

input wire clock,

input wire reset,

input wire package_ready, // пакет был отправлен

output reg [7:0] data_to_eeprom, // данные, которые хотим послать

output reg rw, // читаем или пишем...

output reg data_end // данные для посылок закончились

);

parameter n = 3'b100;

reg [2:0] k;

// states for FSM

localparam INIT = 0,

WRITE = 1,

READ = 2,

DONE = 3;

reg [1:0] current_state, next_state;

always @(posedge clock or posedge reset)

begin

if (reset)

current_state = INIT;

else

current_state = next_state;

end

always @(negedge clock or posedge reset)

begin

if(reset)

k = 0;

else if ((current_state == WRITE) && (package_ready == 1))

k = k + 1'b1;

else if (current_state == READ)

k = 0;

else

k = k;

end

Файл control_unit.v

always @ (*)

begin

case (current_state)

INIT:

begin

data_end = 0;

next_state = WRITE;

rw = 0;

data_to_eeprom = 0;

end

WRITE:

begin

rw = 0;

case (k)

3'b000: begin

data_to_eeprom = 8'b0000_0000;

end

3'b001: begin

data_to_eeprom = 8'b0001_0110;

end

3'b010: begin

data_to_eeprom = 8'b0001_1000;

end

3'b011: begin

data_to_eeprom = 8'b1111_1110;

end

default: begin

data_to_eeprom = 8'b0000_0000;

end

endcase

if (k == n)

begin

next_state = READ;

data_end = 1;

end

else

begin

next_state = WRITE;

data_end = 0;

end

end

READ:

begin

rw = 1;

next_state = DONE;

end

DONE:

begin

next_state = INIT;

end

default:

begin

next_state = INIT;

end

endcase

end

endmodule

Вывод

В результате работы разработан узел, осуществляющий контроль передачи данных через последовательную двухпроводную шину I2c на устройство EEPROM.

░░░░░░░░░░░░▄▀▀▀▄░░░░░░░

░░░░░░░▄███▀░@(◐)░░░▌░░░░░

░░░░░░░░░░░▌░░░░░▐░░░░░

РАБОТЯГИ░░░▌░░░░▐░░░░░░

░░░░░░░░░░░█▀▀░░█░░░░░░

░░░░░░▄▀▀▀▀░░░░░█▄▄░░░░

░░░░░░█░█░░░░░░░░░░▐░░░

░░░░░░▐▐░░░░░░░░░▄░▐░░░

░░░░░░█░░░░░░░░▄▀▀░▐░░░

░░░░▄▀░░░░░░░░▐░▄▄▀░░░░

░░▄▀░░░▐░░░░░█▄▀░▐░░░░░

░░█░░░▐░░░░░░░░▄░█░░░░░

░░░█▄░░▀▄░░░░▄▀▐░█░░░░░

░░░█▐▀▀▀Ỏ▀▀▀▀░░▐░█░░░░░

░░▐█▐▄░░░░░░░░░▐░█▄▄░

Соседние файлы в предмете Интерфейсы Периферийных Устройств