Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VHDL and I2C

Status
Not open for further replies.

JosipBros

Programmer
Jan 21, 2008
2
PL
Hello

i want to make a simple - very simple communication between my FPGA(SPRATAN XC2S300E) and ADC - MAX1037. Therefore i've made such a code:
...
signal frame : STD_LOGIC_VECTOR (9 downto 0);
signal shiftCounter : STD_LOGIC_VECTOR (3 downto 0) :="0000";
signal ADCAdressWR : std_logic_vector (7 downto 0) := "00010011";
signal ADCAdressRD : std_logic_vector (7 downto 0) := "10010011"; signal ADCConfiguration: std_logic_vector (7 downto 0) ;
signal ADCSetup : std_logic_vector (7 downto 0) := "00000001";
...
process(SCL)

begin
frame(0) <= '0'; --uart start bit
frame(9) <= '1';
if rising_edge(SCL) then
for i in 0 to 7 loop
SDA <= ADCAdressWR(i);
end loop;
result(0) <= SDA; -- ACK on LED
for i in 0 to 7 loop
SDA <= ADCSetup(i);
end loop;
result(1) <= SDA;
for i in 0 to 7 loop
SDA <= ADCAdressRD(i);
end loop;
result(2) <= SDA;
for i in 0 to 7 loop
temp(i) <= not SDA;
end loop;
for i in 1 to 8 loop
frame(i) <= temp(i-1);
end loop;
for i in 1 to 8 loop
frame(i) <= temp(i-1);
end loop;
txd <= frame(conv_integer(unsigned(shiftCounter)));
shiftCounter <= shiftCounter +1;
if shiftCounter = "1010" then
shiftCounter <= "0000";
end if;
end process

But it doesnt work. On terminal only thing i can see are 000000000...SCL Clock works in 4,8 kHz

Thanks in advance
 
JosipBros,

From the looks of it you are a software programmer.

When programming VHDL you need to think hardware.

For example you would use a loop to shift in a C program for a microcontroler or processor.

I VHDL you create multiple instances (= parallelism) with a loop.

What you need to do is work with state machines. You need to create a double state machine one that can write or read from the AD.

Writeing will mean setting up address and data and then shifting all the bits out sequentially (this means you remain in a state send where you shift through the data.

For reading this will be first you put the address and then you latch in the bits sequentially.

I do not have the time to write you the code, plus it's more fun to do it yourself. You'll learn more from it.

I also give you the advice to properly read the datasheet of your AD and especially the I²C part.

What you can allways do is look on the web (Xilinx, Altera, ...) for templates or code examples on I²C

If you have further questions just post them here and I'll help you further.

regards

Jeandelfrigo
 
So could You explain me how to in simpliest way send a 8 bit command via 1 bit output ?
 
JosipBros,

Sure,

You do this with a shift register, this is typically a parallel in and serial out register, and of course you can do the same in the other direction.

First some assumptions :

This is only provide you the process code for the shift register.
This is for parallel to serial.
The load and shift control signals are generated by a processor or state machine depending on your application.
Typically the load is one clock cycle high and the shift signal will typically become high for 7 clock cycles starting at the second SClk cycle of the datasegment. Also this means that the clock signal used is 8 times higher in frequency than the sclk signal for the i2c. DataIn is data from the FSM or processor to be sent out (also 8 bit)


so you have in your architecture :

signal shiftreg : std_logic_vector(7 downto 0);
signal shift : std_logic;
signal load : std_logic;


p_shift : process(clk)
begin
if (clk'event and clk = '1')then
if (rst = '1')then
shiftreg <= (others => '1'); -- can also be zero
elsif(load = '1')then
shiftreg <= DataIn;
elsif(shift = '1')then
shiftreg <= '1' & shiftreg(7 downto 1); -- LSB first
end if;
end if;
end process p_shift;

SDA <= shiftreg(0); -- SDA is the I2C datapin

So this is basically a shift register description, it's pretty simple isn't it, and I think the serial to parallel is easily written if you get the code above.

For I2C the trick is in the controlling of this register(s) and also the alignement with the sclk.

Also some remarks :

The reset value of the shiftregister can also be all zero and you can also take a zero in the following statement :

shiftreg <= '0' & shiftreg(7 downto 1); -- LSB first

But you have to know that I2C idle state is '1' for both SDA and SCL so resetting and filling up with '1' is better to avoid any false continued starts or wathever.

Also double check because it could be that you have to shift MSB first, I do not know I2C protocol by heart.

This would go like this:

shiftreg <= shiftreg(6downto 0) & '1'; -- MSB first

SDA <= shiftreg(7);

regards and good luck

jeandelfrigo

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top