Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

TC34725 i2c color sensor not working without any error (basys3 vhdl)

Status
Not open for further replies.

kmesne

Newbie level 5
Joined
Mar 13, 2019
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
146
Hi i implemented a vhdl code for checking results from TCS34725 there is no error in my code and i checked everywhere to correct and make it flawless but it does not work at all.

I am not very good at i2c i just know the main logic behind it so i think my problem is connected to i2c but i dont know

TCS34725 INTERFACE MODULE
Code:
library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;



entity tcs34725_interface is

  generic(



    --The clock frequency of the board you're using.

    --For the Basys board, this is usually 50MHz, or 50_000_000.

    clk_frequency : integer := 100_000_000;



    --The I2C clock frequency. This can be any number below 400kHz for

    --the TCS34725.

    i2c_frequency : integer := 100_000

  );

  port(



    --System clock.

    clk   : in std_logic;

    reset : in std_logic := '0';

    

    --I2C signals.

    sda : inout std_logic;

    scl : inout std_logic;



    --Light sensor reading...

    clear_intensity : out std_logic_vector(15 downto 0);

    red_intensity   : out std_logic_vector(15 downto 0);

    green_intensity : out std_logic_vector(15 downto 0);

    blue_intensity  : out std_logic_vector(15 downto 0)

  );

end tcs34725_interface;



architecture Behavioral of tcs34725_interface is



  --The address of the TCS34725. This device has only one possible address,

  --so we won't genericize it.

  constant address : std_logic_vector := "0101001";



  --Signals for data exchange with the core I2C controller.

  signal data_to_write, last_read_data : std_logic_vector(7 downto 0);

  signal reading, transaction_active, controller_in_use : std_logic;



  --Rising edge detect for the "controller in use" signal.

  --A rising edge of this signal indicates that the I2C controller has accepted our data.

  signal controller_was_in_use    : std_logic;

  signal controller_accepted_data, new_data_available : std_logic;



  --I2C read/write constants.

  constant write : std_logic := '0';

  constant read  : std_logic := '1';



  --I2C commands for the TSL34725.

  constant select_control_register : std_logic_vector := x"80";

  constant power_on                : std_logic_vector := x"03";

  constant read_color_values       : std_logic_vector := x"B4";



  --Core state machine logic.

  type state_type is (STARTUP, SEND_POWER_COMMAND, TURN_POWER_ON,

                      WAIT_BEFORE_READING, SEND_READ_COMMAND, START_READ, 

                      FINISH_READ_AND_CONTINUE, FINISH_READ_AND_RESTART);

  signal state, next_state : state_type := STARTUP;



  --Create a simple read buffer for each of the sequential bytes.

  type byte_buffer is array(natural range <>) of std_logic_vector(7 downto 0);

  signal read_buffer : byte_buffer(7 downto 0);



  --Signal which stores the current index in the byte buffer.

  signal current_byte_number      : integer range 8 downto 0   := 0;

  signal reset_1 : std_logic;

component i2c_master is
GENERIC(
    input_clk : INTEGER := 100_000_000; --input clock speed from user logic in Hz
    bus_clk   : INTEGER := 400_000);   --speed the i2c bus (scl) will run at in Hz
  PORT(
    clk       : IN     STD_LOGIC;                    --system clock
    reset_n   : IN     STD_LOGIC;                    --active low reset
    ena       : IN     STD_LOGIC;                    --latch in command
    addr      : IN     STD_LOGIC_VECTOR(6 DOWNTO 0); --address of target slave
    rw        : IN     STD_LOGIC;                    --'0' is write, '1' is read
    data_wr   : IN     STD_LOGIC_VECTOR(7 DOWNTO 0); --data to write to slave
    busy      : OUT    STD_LOGIC;                    --indicates transaction in progress
    data_rd   : OUT    STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave
    ack_error : BUFFER STD_LOGIC;                    --flag if improper acknowledge from slave
    sda       : INOUT  STD_LOGIC;                    --serial data output of i2c bus
    scl       : INOUT  STD_LOGIC);                   --serial clock output of i2c bus

end component;


begin

reset_1 <= not reset;

  --

  -- Instantiate our I2C controller.

  --

  I2C_CONTROLLER: i2c_master 

  generic map(

    input_clk => 100_000_000, --Our system clock speed, 50MHz.

    bus_clk   => 100_000

  )  

  port map(

		clk       => clk,

		reset_n   => reset_1,

		ena       => transaction_active,

		addr      => address,

		rw        => reading,

		data_wr   => data_to_write,

		busy      => controller_in_use,

		data_rd   => last_read_data,

		ack_error => open,

		sda       => sda,

		scl       => scl

	);



  --

  -- Edge detect for the I2C controller's "in use" signal.

  --

  -- A rising edge of this signal denotes that the controller has accepted our data,

  -- and allows progression of our FSM.

  --

  controller_was_in_use    <= controller_in_use when rising_edge(clk);

  controller_accepted_data <= controller_in_use and not controller_was_in_use;



  --

  -- Output mappings.

  -- The output from the light sensor is recieved as a block of eight bytes,

  -- this breaks that block into Clear/RGB data.

  --

  clear_intensity(15 downto 8) <= read_buffer(1);

  clear_intensity(7  downto 0) <= read_buffer(0);

  red_intensity(15 downto 8)   <= read_buffer(3);

  red_intensity(7  downto 0)   <= read_buffer(2);

  green_intensity(15 downto 8) <= read_buffer(5);

  green_intensity(7  downto 0) <= read_buffer(4);

  blue_intensity(15 downto 8)  <= read_buffer(7);

  blue_intensity(7  downto 0)  <= read_buffer(6);





  --

  -- Main control FSM for the I2C light sensor.

  --

  CONTROL_FSM:

  process(clk)

  begin



    -- If our reset signal is being driven, restar the FSM.

    if reset = '1' then

      state <= state_type'left;



    elsif rising_edge(clk) then



      --Keep the following signals low unless asserted.

      --(This also prevents us from inferring additional memory.)

      data_to_write      <= (others => '0');





      case state is



        --

        -- Wait state.

        -- Waits for the I2C controller to become ready.

        --

        when STARTUP =>



          if controller_in_use = '0' then

            state <= SEND_POWER_COMMAND;

          end if;



        --

        -- First power-on state.

        -- Sets up the initial I2C communication that will enable the device's internal ADC.

        --

        when SEND_POWER_COMMAND =>

          

          --Set up the device to write the first byte of the setup command.

          transaction_active <= '1';

          reading      <= write;



          --Select the device's primary control register.

          data_to_write      <= select_control_register;



          --Wait here for the I2C controller to accept the new transmission, and become busy.

          if controller_accepted_data = '1' then

            state <= TURN_POWER_ON;

          end if;



        --

        -- Second power-on state.

        -- Continues the ADC enable communication.

        --

        when TURN_POWER_ON =>



          --And turn the device's enable on.

          data_to_write      <= power_on;



          --Once the controller has accepted this data,

          --move to the core sensor reading routine.

          if controller_accepted_data = '1' then

            state <= WAIT_BEFORE_READING;

          end if;





        --

        -- Wait for the transmitter to become ready

        -- before starting a second TWI transaction.

        --

        when WAIT_BEFORE_READING =>



          --Ensure we are not transmitting during for a

          --least a short period between readings.

          transaction_active  <= '0';

          current_byte_number <= 0;



          --Wait for the transmitter to become idle.

          if controller_in_use = '0' then

            state <= SEND_READ_COMMAND;

          end if;





        --

        -- Send the "read" command.

        -- This sets up a multi-byte read from the ADC sample register.

        --

        when SEND_READ_COMMAND =>



          --Set up the device to write to the command register,

          --indicating that we want to read multiple bytes from the ADC register.

          transaction_active      <= '1';

          reading                 <= write;

          current_byte_number     <= 0;

          



          --Select the device's primary control register.

          data_to_write      <= read_color_values;



          --Once the controller has accepted the command,

          --move to the state where we'll read from the device itself.

          if controller_accepted_data = '1' then

            state <= START_READ;

          end if;





        --

        -- Start a read of a single byte of ADC data.

        -- In this state, we set up our read data, and wait for the

        -- light sensor to accept it.

        --

        when START_READ =>



          --Set up the device to write to the command register,

          --indicating that we want to read multiple bytes from the ADC register.

          transaction_active      <= '1';

          reading                 <= read;



          --Wait for the controller to accept the read instruction.

          if controller_accepted_data = '1' then

           

            --If we've just initiated our final read, finish the read

            --and then start the read again from the beginning.

            if current_byte_number = read_buffer'high then

              state <= FINISH_READ_AND_RESTART;



            --Otherwise, finish the read, but keep populating the buffer.

            else

              state <= FINISH_READ_AND_CONTINUE;



            end if;

          end if;



        --

        -- Finish a read of a single byte of ADC data,

        -- and then continue reading.

        --

        when FINISH_READ_AND_CONTINUE =>



          --Wait for the I2C controller to finish reading...

          if controller_in_use = '0' then



            --...capture the read result.

            read_buffer(current_byte_number) <= last_read_data;



            --... move to the next spot in the read buffer.

            current_byte_number <= current_byte_number + 1;



            ---... and finish reading.

            state <= START_READ;



          end if;



        

        --

        -- Finish a read of a single byte of ADC data,

        -- and then restart from the beginning of the buffer.

        --

        when FINISH_READ_AND_RESTART =>



          --Since we're not going to continue reading,

          --allow the transaction to end.

          transaction_active <= '0';



          --Wait for the I2C controller to finish reading...

          if controller_in_use = '0' then



            --...capture the read result.

            read_buffer(current_byte_number) <= last_read_data;



            ---... and restart the process.

            state <= WAIT_BEFORE_READING;



          end if;

        end case; 

      end if;

    end process;

end Behavioral;

TOP MODULE

Code:
-- Basys board example of a simple TCS34725 driver.

--

-- Steps to use:

--  --Connect SDA to the left-most pin, which has site location B2.

--  --Connect SCL to the pin directly to the right, which has site location A3.

--  --Connect I2C light sensor to 3.3V power supply. Observe readings on seven-segment

--    display!

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;





entity tcs34725_basys_example is

  port(



    --System clock.

    clk   : in std_logic;

    reset : in std_logic := '0';

    

    --TWI/I2C signals.

    sda : inout std_logic;

    scl : inout std_logic;



    --Color selection inputs

    sw  : in std_logic_vector(1 downto 0);



    -- leds output
    
    leds: out std_logic_vector (15 downto 0)

  );

end tcs34725_basys_example;



architecture Behavioral of tcs34725_basys_example is

  signal clear_intensity, red_intensity,green_intensity, blue_intensity : std_logic_vector(15 downto 0);


component 
tcs34725_interface is

  generic(

    --The clock frequency of the board you're using.

    --For the Basys board, this is usually 50MHz, or 50_000_000.

    clk_frequency : integer := 100_000_000;


    --The I2C clock frequency. This can be any number below 400kHz for

    --the TCS34725.

    i2c_frequency : integer := 100_000

  );

  port(



    --System clock.

    clk   : in std_logic;

    reset : in std_logic := '0';

    
    --I2C signals.

    sda : inout std_logic;

    scl : inout std_logic;


    --Light sensor reading...

    clear_intensity : out std_logic_vector(15 downto 0);

    red_intensity   : out std_logic_vector(15 downto 0);

    green_intensity : out std_logic_vector(15 downto 0);

    blue_intensity  : out std_logic_vector(15 downto 0)

  );
end component;

begin

  --

  -- Instantiate our TCS34725 controller.

  -- 

  SENSOR_INTERFACE: tcs34725_interface generic map(



    --The clock frequency of the board you're using.

    --For the Basys board, this is usually 50MHz, or 50_000_000.

    clk_frequency => 100_000_000,



    --The I2C clock frequency. This can be any number below 400kHz for the TCS34725.

    i2c_frequency => 100_000

  )

  port map(

    clk             => clk,

    reset           => reset,

    sda             => sda,

    scl             => scl,

    clear_intensity => clear_intensity,

    red_intensity   => red_intensity,

    green_intensity => green_intensity,

    blue_intensity  => blue_intensity

  );
  
  -- Simple multiplexer which selects the channel that we're looking at.

  process (sw)
  begin
  
 if sw = "10" then
 leds <= green_intensity;
 elsif sw = "01" then 
 leds <= red_intensity;
 end if;
 end process;
 
end Behavioral;

I used https://www.digikey.com/eewiki/pages/viewpage.action?pageId=10125324 this link for i2c master just changed clock for basys3 100 MHz
 

Hi,

What is your test circuit?
Where are the scope pictures?

there is no error in my code
How can you be that sure?

Klaus
 

Hi i implemented a vhdl code for checking results from TCS34725 there is no error in my code and i checked everywhere to correct and make it flawless but it does not work at all.

Well did you write a testbench and verify the functionality? If you didn't then you can't say there are no (functional) errors in your code.

Is your assessment of your code being flawless and correct is that it can be synthesized?
 

I am not very good at i2c i just know the main logic behind it so i think my problem is connected to i2c but i dont know
Then you must study, learn more and go to the depth of the problem. Else you will not be able to proceed.

As ads-ee has mentioned, write a test-bench and verify your design before testing it on-board.
Break your design into small modules and verify each module independently using test-benches.

Start with the I2C master-slave communication.
 

I dont know how to write testbench for a sensore since its has sda scl inouts.

I was trying to say that there is no error during synthesis
 

I dont know how to write testbench for a sensore since its has sda scl inouts.
It is in principle a I2C slave. So you take a slave i2c module (your sensor), connect it to a master i2c module (your logic which will acquire the data from the sensor) and put the whole thing in a testbench and simulate.

I was trying to say that there is no error during synthesis
That can come later. You must perform functional verification via simulation whether your logic is working as expected or not.
 

Hello,

if I have been in your position I checked first how this sensor is behaving using Arduino. It is very easy to write a skech wihch can comunicate by I2C with sensor. I assume that you are aware that each I2C has its individual addres (one of 128). You can scan I2C bus with scanner (it is Arduino program), in that way you be able to determine your sensor address. After that if comunication is proper you can try to launch application on FPGA.

Of course writing a "test baench" for yor FPGA project is very good idea.

Regards
 

The code seems to work correctly at first sight, most TCS34725 registers hold their default initial values, e.g. minimal integration time and gain. May be sufficient to see zero output with low irradiation.

You could also read the device ID register to check if the I2C interface is working.

I2C slave simulation models can be found on the web, the register layout has to be adapted to TCS34725.

A digital oscilloscope, preferably with I2C decoder, can be used to debug the real sensor communication.

There may be also trivial faults like missing SDA & SCL pull-up or wrong sensor connection.
 

Hello,

are you sure that this I2C addres is actually proper address:

Code:
--The address of the TCS34725. This device has only one possible address,
--so we won't genericize it.

  constant address : std_logic_vector := "0101001";

The easiest way to check this is use of "I2C scanner for Arduino":

https://gist.github.com/tfeldmann/5411375

Regards
 
Last edited:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top