Some time ago, I have been adjusting the SDRAM and VGA drivers. After a long time and referring to a lot of materials, I finally figured out my ideas. However, since I don’t have the relevant hardware circuits, I have put it aside for the time being. Let’s get back to the topic and look at the communication between IICs first.
First of all, IIC communication, UART, and SPI are collectively referred to as serial interface communication, but there are still differences between them, such as the negative level logic of UART, and UART communication does not require a clock, only a specific baud rate is required. SPI and IIC can both have one host and multiple slaves, but IIC is suitable for short-distance transmission, such as inter-chip communication, camera configuration and other scenarios.
To get IIC, first look at the hardware interface of IIC:
As shown in the figure, we know that one IIC host can connect multiple slaves, so the address lines A2, A1, and A0 can implement the chip select function. The function of the WP pin is that when WP is floating or grounded, it means that the EEPROM can be read and written at this time. When WP is connected to the power supply, it can only be read but not written.
The SCL and SDL pins must be pulled up, otherwise the driving capability is insufficient and normal IIC communication cannot be performed.
OK, the hardware interface has been clearly introduced, so now we can start to look at the protocol.
First of all, IIC is divided into byte reading and writing and page reading and writing. First, let's look at the byte reading and writing protocol:
As shown in the figure above, if we want to write a byte of data to the EEPROM, we have to follow the following steps:
1. Start signal - when SCLK is high, the SDA signal is pulled low (from 1 to 0).
2. Control byte - that is, the device address, which is the EEPROM you are operating.
3.ACK signal - sent by the slave and received by the host, so at this stage, sda_link must be set to 0, that is, to read this response signal, so during the high point of SCLK.
4. Byte address——that is, which address in a certain EEPROM.
5.ACK signal - same as above.
6. Data signal - that is, the 8-bit data you write to a certain address.
7.ACK signal——same as above.
8. End signal - During the high level period of SCLK, pull up the SDA signal to indicate the end of communication.
Let's look at the reading sequence:
It can be seen from the above figure that the previous processing method of the read timing is the same as that of the write timing. The difference is that after the third ACK signal comes, if it is a read, there will be another start signal, followed by the read device address, then the response, then the read data, and then a NO ACK signal is sent during the low level of SCLK. Remember that this signal is sent by the host, followed by an end signal.
From the above read and write timing, we can know that the start of communication jumps during the high level of SCLK. This determines that our other signal jumps are all on the falling edge of SCLK. The data is stable during the high level of SCLK, which is suitable for reading (that is, low level changes data, high level collects data).
The specific process is as follows:
First, a delay is required for the board to be initialized after powering on. You can use a counter to determine the specific delay.
code show as below:
reg [6:0] hadware_initial_delay;
wire hadware_initial_delay_done;
always@(posedge clk or negedge rst_n)
if(!rst_n)
hadware_initial_delay<=7'd0;
else
if(hadware_initial_delay<=7'd49)
hadware_initial_delay<=hadware_initial_delay+1;
else
hadware_initial_delay<=hadware_initial_delay;
assign hadware_initial_delay_done=(hadware_initial_delay==7'd50)?1'b1:1'b0;
OK, we need to know that the IIC rate is generally a few hundred KH and our system clock is 50M, so we need to divide the frequency:
code show as below:
reg [8:0] sclk_cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
sclk_cnt<=9'd0;
else
if(hadware_initial_delay_done)
begin
if(sclk_cnt<9'd499)
sclk_cnt<=sclk_cnt+1;
else
sclk_cnt<=0;
end
assign sclk=(sclk_cnt<=9'd249)?1'b1:1'b0;
OK, we know that data is collected during the high level of SCLK, and data is changed during the low level. Of course, this "period" must be the best in the middle of the clock edge. After all, it is easier to meet the setup time and hold time, and it is very stable.
The specific code is as follows:
wire sclk_posedge_middle=(sclk_cnt==9'd124)?1'b1:1'b0;
wire sclk_negedge_middle=(sclk_cnt==9'd374)?1'b1:1'b0;
OK, there are so many processes defined for reading and writing, of course a state machine is needed to handle it, and the variables are defined as follows:
parameter IDLE = 4'd0;
parameter START1 = 4'd1;
parameter ADD1 = 4'd2;
parameter ACK1 = 4'd3 ;
parameter ADD2 = 4'd4;
parameter ACK2 = 4'd5 ;
parameter DATA = 4'd6;
parameter ACK3 = 4'd7;
parameter STOP1 = 4'd8;
parameter START2 = 4'd9;
parameter ADD3 = 4'd10;
parameter ACK4 = 4'd11;
parameter DATA_READ = 4'd12;
parameter NO_ACK = 4'd13;
parameter STOP2 = 4'd14;
OK, here is another macro definition, assuming that the addresses and data to be written are these.
define DEVICE_READ 8'b1010_0001
define DEVICE_WRITE 8'b1010_0000
define WRITE_DATA 8'b0001_0001
define BYTE_ADDR 8'b0000_0011
SDA bidirectional port, remember this, generally do it like this;
reg sda_link;
reg sda_out_r;
assign sda=sda_link?sda_out_r:1'bz;
When used as an output, right, sda_link is pulled high, and when used as an input, the input is high impedance.
The processes are as follows:
reg [3:0] current_state;
//reg [3:0] next_state;
reg [7:0] db_r;
reg [3:0] num;
reg [7:0] data_out_reg;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
sda_link<=0;
db_r<=0;
num<=0;
current_state<=IDLE;
sda_out_r<=0;
data_out_reg<=8'b0;
end
else
begin
case(current_state)
IDLE:begin
sda_out_r<=1;
sda_link<=1;
if(!sw1_r||!sw2_r)
current_state<=START1;
else
current_state<=IDLE;
end
START1:if(sclk_posedge_middle)
begin
sda_out_r<=0;
db_r<=`DEVICE_WRITE;
current_state<=ADD1;
end
else
current_state<=START1;
ADD1:
if(sclk_negedge_middle)
begin
if(num==4'd8)
begin
sda_link<=0;
num<=0;
current_state<=ACK1;
sda_out_r<=1;
end
else
begin
current_state<=ADD1;
sda_out_r<=db_r[7-num];
num<=num+1;
end
end
else
current_state<=ADD1;
ACK1:
if(sclk_posedge_middle)
// begin
// if(!sda)
// begin
begin // */
current_state<=ADD2;
db_r<=`BYTE_ADDR;
end
else
current_state<=ACK1;
ADD2:begin
sda_link<=1;
if(sclk_negedge_middle)begin
if(num==4'd8)
begin
sda_link<=0;
current_state<=ACK2;
num<=4'd0;
sda_out_r<=1;
end
else
begin
num<=num+1;
current_state<=ADD2;
sda_out_r<=db_r[7-num];
end
end
else
current_state<=ADD2;
end
ACK2:
if(sclk_posedge_middle)
////begin
//if(!sda)
begin
if(!sw1_r)
begin
db_r<=`WRITE_DATA;
current_state<=DATA;
end
else
if(!sw2_r)
begin
current_state<=START2;
sda_out_r<=1;
end
end
else
current_state<=ACK2;
DATA: begin
sda_link<=1;
if(sclk_negedge_middle)
begin
if(num==4'd8)
begin
num<=4'd0;
current_state<=ACK3;
sda_out_r<=1;
sda_link<=0;
end
else
begin
num<=num+1;
current_state<=DATA;
sda_out_r<=db_r[7-num];
end
end
else
current_state<=DATA;
end
ACK3: if(sclk_posedge_middle)
// begin
// if(!sda)
current_state<=STOP1;
// end
STOP1:
begin
sda_link<=1;
sda_out_r<=0;
if(sclk_posedge_middle)
begin
sda_out_r<=1;
if(sw1_r)
// If you don't wait for it to be released before restoring the initial state, then once you restore the initial state SW1_r will be low, and it will start writing again, so as to avoid repeated writing of data.
current_state<=IDLE;
else
current_state<=STOP1;
end
else
current_state<=STOP1;
end
START2:begin
sda_link<=1;
if(sclk_posedge_middle)
begin
sda_out_r<=0;
sda_link<=1;
db_r<=`DEVICE_READ;
current_state<=ADD3;
end
end
ADD3: begin
if(sclk_negedge_middle)
begin
if(num==4'd8)
begin
num<=0;
sda_link<=0;
sda_out_r<=1;
current_state<=ACK4;
end
else
begin
num<=num+1;
sda_out_r<=db_r[7-num];
current_state<=ADD3;
end
end
else
current_state<=ADD3;
end
ACK4:
if(sclk_posedge_middle)
// begin
// if(!sda)
current_state<=DATA_READ;
else
current_state<=ACK4;
// end
DATA_READ:
begin
sda_link<=0;
if(sclk_posedge_middle)
begin
if(num==4'd8)
begin
sda_link<=1;
sda_out_r<=1;
current_state<=NO_ACK;
num<=4'd0;
end
else
begin
num<=num+1;
current_state<=DATA_READ;
data_out_reg[7-num]<=sda;
end
end
end
NO_ACK:
if(sclk_negedge_middle)
begin
sda_out_r<=1;
current_state<=STOP2;
end
else
current_state<=NO_ACK;
STOP2: begin
sda_out_r<=0;
sda_link<=1;
if(sclk_posedge_middle)
begin
sda_out_r<=1;
current_state<=IDLE;
end
else
current_state<=STOP2;
end
default:current_state<=IDLE;
endcase
end
assign data_out=data_out_reg;
endmodule
The simulation results are as follows:
OK, done. The output can of course be connected to a digital tube, LED, etc. to show whether it is correct.
Previous article:The difference between master-slave communication between standard IIC and IO port simulated IIC
Next article:Understanding of IIC during GPIO simulation of IIC
Recommended ReadingLatest update time:2024-11-16 14:32
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Has anyone used a 15v to 3.3v converter?
- When low EMI power supplies meet crowded circuit boards, what do you do?
- EEWORLD University ---- OpenCV 3 with Python 3 Tutorial
- Siemens 230RC opens for 3 seconds and closes for 3 seconds
- Stack Overflow Technology from Entry to Mastery
- Design of Automatic AC Voltage Stabilizer
- Competition control competition materials and excellent works sharing
- NUCLEO_G431RB Review (1) Compilation Environment Settings
- EEWORLD University - Practical Application of IoT in Vehicles
- Memory Compression Technology in Embedded Systems