08-27-2012 05:09 AM
Hi, I am trying to send data to MCP4725 DAC by using a simple and self-written i2c protocol but I could not reach my goal whatever I try. I get no errors.
Can someone help me get through this?
Thx in advance.
I am using Spartan 3E-nexys2 1200k board and here my code:
----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity I2C_master is
port (clkin : in std_logic;
scl : out std_logic;
sda : inout std_logic);
end I2C_master;
architecture Behavioral of I2C_master is
signal state, state_temp : unsigned (4 downto 0) := "00000";
signal ack, clk, clkout, sda_sent, sda_received : std_logic;
constant device_addr : std_logic_vector (10 downto 0) := "11000000000";
constant din : std_logic_vector (11 downto 0) := x"000";
begin
----clock generation, using standart mode up to 100Kbits
CLOCK_GEN: process (clkin)
variable counter : integer := 0;
begin
if rising_edge(clkin) then
if counter = 500 then
counter := 0;
clkout <= '1';
else
clkout <= '0';
counter := counter +1;
end if;
end if;
end process;
--din generator
--DIN_GEN: process (state)
--begin
-- if state = idle then
-- din <= din + 1;
-- end if;
--end process;
--write
DATA_WRITE: process(clkout, sda_received )
variable count : integer;
begin
if rising_edge (clkout) then
--start
if state = 0 then
clk <= '1';
sda_sent <= '1';
state <= state + 1;
elsif state = 1 then
sda_sent <= '0';
state <= state + 1;
clk <= '0';
--first 7 bits of address
elsif state >= 2 and state <= 8 then
clk <= '1';
count := conv_integer(state);
sda_sent <= device_addr(12-count);
state_temp <= state + 1;
state <= "11111";
--write command inserted
elsif state = 9 then
clk <= '1';
sda_sent <= '0';
state_temp <= state + 1;
state <= "11111";
--ack1 received
elsif state = 10 then
clk <= '1';
ack <= '1';
if sda_received = '0' then --ack1 received
ack <= '0';
state_temp <= state + 1;
state <= "11111";
else
clk <= '0';
state <= "00000";
end if;
--remaining 4 bits of address
elsif state >= 11 and state <= 14 then
clk <= '1';
count := conv_integer(state);
sda_sent <= device_addr(14-count);
state_temp <= state + 1;
state <= "11111";
--first 4 data bits
elsif state >= 15 and state <= 18 then
clk <= '1';
count := conv_integer(state);
sda_sent <= din(26-count);
state_temp <= state + 1;
state <= "11111";
--ack2 received
elsif state = 19 then
clk <= '1';
ack <= '1';
if sda_received = '0' then --ack2 received
ack <= '0';
state_temp <= state + 1;
state <= "11111";
else
clk <= '0';
state <= "00000";
end if;
--remaining 8 bits of data
elsif state >= 20 and state <= 27 then
clk <= '1';
count := conv_integer(state);
sda_sent <= din(27-count);
state_temp <= state + 1;
state <= "11111";
--ack3 received
elsif state = 28 then
clk <= '1';
ack <= '1';
if sda_received = '0' then --ack3 received
ack <= '0';
state_temp <= state + 1;
state <= "11111";
else
clk <= '0';
state <= "00000";
end if;
--stop
elsif state = 29 then
clk <= '1';
sda_sent <= '0';
state <= state + 1;
elsif state = 30 then
clk <= '1';
sda_sent <= '1';
state <= "00000";
-----------------------------------
--wait option, to pull clock to zero
elsif state = 31 then
state <= state_temp;
clk <= '0';
end if;
end if;
end process;
sda_received <= sda when ack = '1' else 'Z';
sda <= sda_sent;
scl <= clk;
end Behavioral;
08-27-2012 10:29 AM
1. It is difficult to read code which is not formatted to be readable. Please, either use the code insertion button, or use the fixed-pitch COURIER NEW font for the source code.
2. You have posted perhaps 100 lines of code without describing the problem for which we should be searching. Please describe the problem. "It does not work" is not a very good description.
3. Have you simulated your design? If not, this can be a valuable debugging tool for this application.
4. Have you applied an oscilloscope to the I2C signals? If not, this can be a valuable debugging tool for this application.
-- Bob Elkind
08-27-2012 04:26 PM
Thx for the reply.
1- My code is readable actually but when I paste it it becomes like that. So I attached .vhd file. I am basically trying to send hex"000" to 12-bit DAC mcp4725 which uses i2c interface and see 0 (zero) at the analog output. I use standart mode up to 100Kbits.
2- Sorry for the lack of info, but I myself am not sure about the problem. I assigned scl and sda to leds and increase the period for debugging. The signal sequence is just as I expect. However when it comes to the real hardware application I do not see the expected output. Maybe I am doing something wrong with the hardware. Do I need to use pull-ups (or something similar) for pmod pins (JA, spartan3E-nexys2)? Also I am not comfortable with INOUT pin. Did I make some mistake when using inout?
3- I tried but I am not good at analyzing simulations. I will try chipscope.
4- I do not have an oscilloscope right now (I am in summer break) so I could not try it yet.
08-27-2012 05:42 PM - edited 08-27-2012 05:43 PM
You have a number of problems.
Have you read through some of the previous user forum threads discussing I2C?
In the New Users Forum README thread, you will find this:
Common Interfaces and FPGA techniques:
I2C basics link#1 link#2 code examples I2C spec Rev 4 wiki articles: I2C SMBus MDIO SPD EDID
I assigned scl and sda to leds and increase the period for debugging. The signal sequence is just as I expect. However when it comes to the real hardware application I do not see the expected output. Maybe I am doing something wrong with the hardware. Do I need to use pull-ups (or something similar) for pmod pins (JA, spartan3E-nexys2)? Also I am not comfortable with INOUT pin. Did I make some mistake when using inout?
This should help you for a while. The signaling levels/drive problem cannot be understood using ChipScope, as ChipScope does not directly access external signals or pins.
-- Bob Elkind