Question

I am trying to code a i2c like bus on a spartan 6. I have a bunch of states that i time using the folowing counter.

  -- Timer --
  TimesUp <=  true when TmrCnt = 0 else
             false when TmrCnt /= 0 else
             false;
  tmrProc: process(ClkxC, SetTmr, TmrInit)
  begin
    if (rising_edge(ClkxC)) then
      if (SetTmr = '1') then
        TmrCnt <= TmrInit;
      elsif (TmrCnt > 0) then
        TmrCnt <= TmrCnt - 1;
      end if;
    end if;
  end process;

The problem is that my state machine is clocked on the same clock and for some short duration states it just blasts through as if the timer is not set in time.

So I tried this:

  -- Timer --
  TimesUp <=  true when TmrCnt = 0 else
             false when TmrCnt /= 0 else
             false;
  tmrProc: process(ClkxC, SetTmr, TmrInit)
  begin
    if (SetTmr = '1') then
      TmrCnt <= TmrInit;
    elsif (rising_edge(ClkxC)) then 
      if (TmrCnt > 0) then
        TmrCnt <= TmrCnt - 1;
      end if;
    end if;
  end process;

Now it simulates just fine, but when I try to implement i get an error message saying that:

   This design contains one or more registers/latches that are directly
   incompatible with the Spartan6 architecture. The two primary causes of this is
   either a register or latch described with both an asynchronous set and
   asynchronous reset, or a register or latch described with an asynchronous
   set or reset which however has an initialization value of the opposite 
   polarity (i.e. asynchronous reset with an initialization value of 1).

I really don't know how to make the timer load fast enough without braking the rules of the spartan 6.

Was it helpful?

Solution

The warning has been explicitly described in Xilinx WP309 Targeting and Retargeting Guide for Spartan-6 FPGAs [P9-11].

To reduce cost of the overall architecture, slices in Spartan-6 FPGAs do not have a REV 
pin. As a result, flip-flops no longer implement both a set signal and a reset signal. In 
addition, a register with a set or reset signal can only have an initialization value of  
the same polarity. For example, a flip-flop with an asynchronous reset can only have an 
initialization value of 0.  

That is to say, the following kinds of registers/latches are NOT RECOMMENDED when using Xilinx Spartan-6 FPGAs:

      ______|______  
      |    Set    |  
      |           |
   ---| D       Q |---      -- 1. a register/latch with both ASYNCHRONOUS
      |         _ |               set and reset signals
   ---|>Clk     Q |o--      -- NOT RECOMMENDED
      |           |               
      |   Reset   |
      |___________|
            |



    -- 2. a register/latch described with an ASYNCHRONOUS set/reset which
          however has an initialization value of the opposite polarity 

    -- The default value of reg is 0 which is the left
    -- bound value of the integer type definition.
    signal reg: integer range 0 to 7;   <-----
                                              |
    process (clk, reset)                      |___  opposite
    begin                                     |     NOT RECOMMENDED
       if (reset = '0') then                  |
          reg <= 7;                     <-----
       elsif ( rising_edge(clk) ) then
          reg <= val; 
       end if;
    end process;

Solutions recommended by Xilinx:

 1. Remove either the set or reset from all registers and latches
    if not needed for required functionality
 2. Modify the code in order to produce a synchronous set and/or 
    reset (both is preferred)
 3. Ensure all registers have the same initialization value as the 
    described asynchronous set or reset polarity
 4. Use the -async_to_sync option to transform the asynchronous
    set/reset to synchronous operation
    (timing simulation highly recommended when using this option)

In your design, you can either initialize TmrCnt to TmrInit or count TmrCnt in an upward direction.

OTHER TIPS

Moving from the first (synchronous) approach to the second (asynchronous set) is rarely the right way to solve the problem; regardless of the Spartan-6 economies on reset logic. Indeed I would justify them on grounds of ... "don't do that".

Instead, look at the statement "The problem is that my state machine is clocked on the same clock and for some short duration states it just blasts through as if the timer is not set in time."

Firstly, there is nothing short duration about I2C signals, unless perhaps this is a multi-hundred MHz derivative of it...

Secondly, one thing VHDL does really well is synchronous design, so "blasting through" without resetting the counter points at something else : possibly the signal assignment rules referred to here.

I suspect this is causing issues where the state machine is setting SetTmr to communicate with the counter in a separate process; so the counter sees SetTmr one cycle later, and that cycle delay is causing the observed mis-behaviour because TimesUp has the wrong value during that cycle.

One answer - a pattern I use a lot - is simply to roll the timer into the SM process itself; then you set it directly and save the handshaking logic and a separate process...

StateMch : process(Clock)
  begin
    if rising_edge(Clock) then
      -- default actions
      if Timer > 0 then 
        Timer <= Timer - 1;
      end if;

      -- state machine
      case State is
      when Start_Wait =>
        Timer <= My_Delay;
        State <= Waiting;
      when Waiting =>
        if Timer = 0 then
          State <= Done;
        end if;
      when others => 
        State <= Start_Wait;
      end case;

    end if;
  end process;

Apart from being simpler and (I find) easier to understand than a huge collection of tiny processes, this allows several states to use the same timer to generate different delays.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top