Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- Linked List
- test bench
- D Flip Flop
- Algorithm
- behavioral modeling
- Edge Detector
- hc-sr04
- ATMEGA128A
- gpio
- vivado
- KEYPAD
- uart 통신
- verilog
- LED
- i2c 통신
- java
- structural modeling
- atmega 128a
- Recursion
- ring counter
- DHT11
- dataflow modeling
- FND
- prescaling
- soc 설계
- stop watch
- BASYS3
- half adder
- Pspice
- pwm
Archives
- Today
- Total
거북이처럼 천천히
I2C 통신을 통한 EEPROM Read/Write (수정 중) 본문
1. 과제
2. 인자값으로 전달 받은 8bit 값을 I2C 통신을 통해 전송하는 모듈 설계
2.1) Input / Output 설정
- sned_8bit_data_spi 모듈은 parameter값으로 전달 받은 8bit memory_data_in 값을 I2C 통신을 통해 전송하는 모듈이다. ( 이름은 SPI로 되어 있으나, I2C 통신을 사용한다. 최근 SPI 통신을 하다보니, SPI 라고 잘못 적었다. ㅠㅠ )
- 해당 모듈은 다음과 같은 Input / Output 값을 갖는다.
Input
→ clk : FPGA System Clock (100MHz)
→ reset_p : System Positive edge reset
→ comm_go : Positive edge가 발생할 시, I2C 통신 시작하는 플래그
→ read_write : R/W Bit
→ Slave address : External Slave Module의 주소
→ memory address : EEPROM의 메모리 주소
→ memory data in : 해당 주소에 쓸 데이터
Output
→ memory_data_out : 읽기 작업 수행할 시, 저장되어 있던 데이터
→ scl, sda
2.2) FSM에서 State 정의
- 해당 EEPROM에서 Read/Write 작업을 수행하기 위해서는 다음과 같은 프로세스를 수행하게 된다.
- 이에 따라 Finite State Machine에서의 State을 다음과 같이 9단계로 정의하였다.
// Declare parameter of state\-machine
parameter S_IDLE = 4'd0;
parameter S_START = 4'd1;
parameter S_SEND_DEVICE_ADDR = 4'd2;
parameter S_WAIT_ACK = 4'd3;
parameter S_SEND_WORD_ADDR = 4'd4;
parameter S_START_FOR_READ = 4'd5;
parameter S_SEND_DEVICE_ADDR_READ = 4'd6;
parameter S_SEND_DATA = 4'd7;
parameter S_STOP = 4'd8;
parameter S_END = 4'd9;
2. 코드
2.1) Send_8bit_data_spi
- 해당 함수는 전달 받은 EEPROM의 주소에 접근하여 데이터를 읽기/쓰기 작업을 수행하는 모듈이다.
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/02/26 08:48:52
// Design Name:
// Module Name: send_8bit_data_spi
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module send_8bit_data_spi(
input clk, reset_p,
input comm_go,
input [6:0] slave_address,
input read_write,
input [7:0] memory_address,
input [7:0] memory_data_in,
inout sda,
output reg scl,
output reg [7:0] memory_data_out);
// Declare parameter of state\-machine
parameter S_IDLE = 4'd0;
parameter S_START = 4'd1;
parameter S_SEND_DEVICE_ADDR = 4'd2;
parameter S_WAIT_ACK = 4'd3;
parameter S_SEND_WORD_ADDR = 4'd4;
parameter S_START_FOR_READ = 4'd5;
parameter S_SEND_DEVICE_ADDR_READ = 4'd6;
parameter S_SEND_DATA = 4'd7;
parameter S_STOP = 4'd8;
parameter S_END = 4'd9;
// Declare current state, next state register
reg [8:0] state, next_state;
// 다음 상태 전이되는가?
always @(posedge clk or posedge reset_p) begin
if(reset_p) state = S_IDLE;
else state = next_state;
end
// Detect positive/negative edge of SCL
wire clk_1usec_nedge;
prescale_100 prescale_100_1usc(.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_1usec_nedge));
// Control SCL Signal & SCL Enable
reg [2:0] scl_5us_counter;
reg scl_enable;
reg [10:0] stop_bit_delay_time;
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
scl = 1;
scl_5us_counter = 0;
end
else if(scl_enable && clk_1usec_nedge) begin
if(scl_5us_counter >= 4) begin
scl_5us_counter = 0;
scl = ~scl;
end
else scl_5us_counter = scl_5us_counter + 1;
end
else if(!scl_enable) begin
scl_5us_counter = 0;
scl = 1;
end
end
// Get positive edge of comm_go
wire comm_go_pedge;
edge_detector edge_detector_comm_go (.clk(clk), .reset_p(reset_p), .cp(comm_go), .p_edge(comm_go_pedge));
// Get positive/negative edge of SCL
wire scl_pedge, scl_nedge;
edge_detector edge_detector_scl (.clk(clk), .reset_p(reset_p), .cp(scl), .n_edge(scl_nedge), .p_edge(scl_pedge));
// Declare variables
wire [7:0] slave_addr_and_RW_bit = {slave_address, read_write};
wire [7:0] device_address = {slave_address, 1'b0};
reg [3:0] idx_send_data;
reg [2:0] flag_ack;
reg [7:0] received_data;
// SDA inout이기 때문에 레지스터를 통한 접근 필요
reg sda_instead;
assign sda = sda_instead;
// State-Machine of I2C
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
sda_instead = 1;
next_state = S_IDLE;
scl_enable = 0;
idx_send_data = 0;
flag_ack = 0;
stop_bit_delay_time = 0;
end
else begin
case(state)
// *** State 1 : IDLE
S_IDLE : begin
sda_instead = 1;
scl_enable = 0;
if(comm_go_pedge) next_state = S_START;
end
// *** State 2 : Start (SDA Signal Negative edge)
S_START : begin
sda_instead = 0;
next_state = S_SEND_DEVICE_ADDR;
end
// *** State 3 : Send the data (Slave Address + R/W bit)
S_SEND_DEVICE_ADDR : begin
scl_enable = 1;
if (scl_nedge) sda_instead = device_address[7 - idx_send_data];
else if (scl_pedge) begin
if (idx_send_data == 7) begin
next_state = S_WAIT_ACK;
idx_send_data = 0;
end else begin
idx_send_data = idx_send_data + 1;
end
end
end
// *** State 4 : Wait ACK signal
S_WAIT_ACK : begin
// Master의 SDA 값을 임피던스 상태로 변환
if(scl_nedge) sda_instead = 'bz;
else if(scl_pedge && !sda) begin
if(flag_ack == 3'd0) begin
next_state = S_SEND_WORD_ADDR;
flag_ack = 3'd1;
end
else if(flag_ack == 3'd1) begin
if(!read_write) begin
next_state = S_SEND_DATA;
flag_ack = 3'd3;
end else begin
next_state = S_START_FOR_READ;
flag_ack = 3'd2;
end
end
else if(flag_ack == 3'd2) begin
next_state = S_SEND_DATA;
flag_ack = 3'd3;
end
else if(flag_ack == 3'd3) begin
next_state = S_STOP;
flag_ack = 3'd0;
end
end
else if(scl_pedge && sda) begin
next_state = S_END;
flag_ack = 3'd0;
end
end
// *** State 5 : Send Word Address
S_SEND_WORD_ADDR : begin
if (scl_nedge) sda_instead = memory_address[7 - idx_send_data];
else if (scl_pedge) begin
if (idx_send_data == 7) begin
next_state = S_WAIT_ACK;
idx_send_data = 0;
end else begin
idx_send_data = idx_send_data + 1;
end
end
end
// *** State 6 : Send Re-start signal
S_START_FOR_READ : begin
if(scl_nedge) sda_instead = 1;
else if(scl_pedge) begin
sda_instead = 0;
next_state = S_SEND_DEVICE_ADDR_READ;
end
end
// *** State 7 : Send Device Address for Read bit
S_SEND_DEVICE_ADDR_READ : begin
if (scl_nedge) sda_instead = slave_addr_and_RW_bit[7 - idx_send_data];
else if (scl_pedge) begin
if (idx_send_data == 7) begin
next_state = S_WAIT_ACK;
idx_send_data = 0;
end else begin
idx_send_data = idx_send_data + 1;
end
end
end
// *** State 8 : Send data
S_SEND_DATA : begin
if(read_write) begin
if(scl_nedge) idx_send_data = idx_send_data + 1;
else if(scl_pedge) begin
if(idx_send_data == 9) begin
idx_send_data = 0;
next_state = S_WAIT_ACK;
end
else received_data[8 - idx_send_data] = sda;
end
end
else begin
if (scl_nedge) sda_instead = memory_data_in[7 - idx_send_data];
else if (scl_pedge) begin
if (idx_send_data == 7) begin
next_state = S_WAIT_ACK;
idx_send_data = 0;
end else begin
idx_send_data = idx_send_data + 1;
end
end
end
end
// *** State 6 : Stop I2C (SDA positive edge)
S_STOP : begin
if(scl_nedge) sda_instead = 0;
else if(scl_pedge) begin
next_state = S_END;
end
end
// *** State 7 : End I2C :
S_END : begin
scl_enable = 0;
if(stop_bit_delay_time <= 999) begin
stop_bit_delay_time = stop_bit_delay_time + 1;
sda_instead = 0;
end
else begin
sda_instead = 1;
scl_enable = 0;
idx_send_data = 0;
next_state = S_IDLE;
stop_bit_delay_time = 0;
memory_data_out = received_data;
end
end
endcase
end
end
// Declare Register variable for SDA
// SDA는 inout 자료형이기 때문에 어떤 값이 들어 올 지 모르기 때문에
reg reg_sda;
always @(posedge clk or posedge reset_p) begin
if(reset_p) reg_sda = 1;
else reg_sda = sda;
end
// ************** ILA IP **************
ila_0 ila_instance (.clk(clk), .probe0(scl), .probe1(reg_sda));
endmodule
2.2) Top Module
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/02/26 08:30:18
// Design Name:
// Module Name: top_of_module
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module top_of_module(
input clk, reset_p,
inout sda,
output scl);
// ************** Declare variables **************
wire clk_out;
wire enable, read_write;
wire [6:0] slave_address;
wire [7:0] memory_address, memory_data_in, memory_data_out;
wire reset_n;
assign reset_n = ~reset_p;
// ************** clk_wiz IP **************
clk_wiz_0 clk_wiz_0_instance0 (
// Clock out ports
.clk_out1(clk_out), // output clk_out1
// Status and control signals
.reset(reset_n), // input reset
.locked(locked), // output locked
// Clock in ports
.clk_in1(clk)); // input clk_in1
// INST_TAG_END ------ End INSTANTIATION Template ---------
// ************** vio_0 IP **************
vio_0 vio_0_instance0 (
.clk(clk_out), // input wire clk
.probe_in0(memory_data_out), // input wire [7 : 0] probe_in0 (## Memory Data Output ##)
.probe_out0(enable), // output wire [0 : 0] probe_out0 (## Enable ##)
.probe_out1(slave_address), // output wire [6 : 0] probe_out1 (## Slave Address ##)
.probe_out2(read_write), // output wire [0 : 0] probe_out2 (## Read & Write ##)
.probe_out3(memory_address), // output wire [7 : 0] probe_out3 (## Memory Address ##)
.probe_out4(memory_data_in) // output wire [7 : 0] probe_out4 (## Memory Data Input ##)
);
// ************** Instance of SPI **************
send_8bit_data_spi spi_send_8bit_instance_0 (.clk(clk_out), .reset_p(reset_n), .comm_go(enable),
.slave_address(slave_address), .read_write(read_write), .memory_address(memory_address),
.memory_data_in(memory_data_in), .scl(scl), .sda(sda), .memory_data_out(memory_data_out));
endmodule
'RTL Design > Verilog 프로젝트' 카테고리의 다른 글
Verilog 팀 프로젝트 - 에너지 절약 선풍기 (1) | 2024.10.05 |
---|---|
Verilog 팀 프로젝트 - 스마트 수경재배기 (0) | 2024.09.10 |
개인 프로젝트 - 스마트 선풍기 만들기 (1) (0) | 2024.08.21 |
통합 시계 (0) | 2024.07.30 |