Перейти к содержанию
    

Непонятный момент

Есть пример использования драйвера

WHEN get_data =>                               
    busy_prev <= i2c_busy;                       
    IF(busy_prev = '0' AND i2c_busy = '1') THEN 
        busy_cnt := busy_cnt + 1;                    
    END IF;
    CASE busy_cnt IS                             
      WHEN 0 =>    
      -------------------
      WHEN 1 =>    
      --------------------

судя по коду busy_cnt это variable и обновиться на busy_cnt := busy_cnt + 1;  и мы никогда не попадем в WHEN 0 => . или все таки busy_cnt обновиться на следующем клоке?

Изменено пользователем jenya7

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А Вы знаете в чем разница  между variable и signal ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

21 minutes ago, jenya7 said:

судя по коду busy_cnt это variable и обновиться на busy_cnt := busy_cnt + 1;  и мы никогда не попадем в WHEN 0 => . или все таки busy_cnt обновиться на следующем клоке?

busy_cnt  обновится  сразу при инкременте.  Но в 0 вы можете попасть если вдруг  условие (busy_prev = '0' AND i2c_busy = '1') не будет выполнено при первом заходе в get_data (если конечно busy_cnt  при этом нулевой).   А как оно действительно  нужно по алгоритму вам виднее. Так как нам не  виден весь "слон" которого вы  грызете. :unknw:

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, RobFPGA said:

Приветствую!

busy_cnt  обновится  сразу при инкременте.  Но в 0 вы можете попасть если вдруг  условие (busy_prev = '0' AND i2c_busy = '1') не будет выполнено при первом заходе в get_data (если конечно busy_cnt  при этом нулевой).   А как оно действительно  нужно по алгоритму вам виднее. Так как нам не  виден весь "слон" которого вы  грызете. :unknw:

Удачи! Rob.

спасибо. слон он для меня слон, а для кого то Моська :)

просто есть I2C драйвер, который мне понравился

Spoiler

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY i2c_master IS
  GENERIC(
    input_clk : INTEGER := 50_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 i2c_master;

ARCHITECTURE logic OF i2c_master IS
  CONSTANT divider  :  INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl
  TYPE machine IS(ready, start, command, slv_ack1, wr, rd, slv_ack2, mstr_ack, stop); --needed states
  SIGNAL state         : machine;                        --state machine
  SIGNAL data_clk      : STD_LOGIC;                      --data clock for sda
  SIGNAL data_clk_prev : STD_LOGIC;                      --data clock during previous system clock
  SIGNAL scl_clk       : STD_LOGIC;                      --constantly running internal scl
  SIGNAL scl_ena       : STD_LOGIC := '0';               --enables internal scl to output
  SIGNAL sda_int       : STD_LOGIC := '1';               --internal sda
  SIGNAL sda_ena_n     : STD_LOGIC;                      --enables internal sda to output
  SIGNAL addr_rw       : STD_LOGIC_VECTOR(7 DOWNTO 0);   --latched in address and read/write
  SIGNAL data_tx       : STD_LOGIC_VECTOR(7 DOWNTO 0);   --latched in data to write to slave
  SIGNAL data_rx       : STD_LOGIC_VECTOR(7 DOWNTO 0);   --data received from slave
  SIGNAL bit_cnt       : INTEGER RANGE 0 TO 7 := 7;      --tracks bit number in transaction
  SIGNAL stretch       : STD_LOGIC := '0';               --identifies if slave is stretching scl
BEGIN

  --generate the timing for the bus clock (scl_clk) and the data clock (data_clk)
  PROCESS(clk, reset_n)
    VARIABLE count  :  INTEGER RANGE 0 TO divider*4;  --timing for clock generation
  BEGIN
    IF(reset_n = '0') THEN                --reset asserted
      stretch <= '0';
      count := 0;
    ELSIF(clk'EVENT AND clk = '1') THEN
      data_clk_prev <= data_clk;          --store previous value of data clock
      IF(count = divider*4-1) THEN        --end of timing cycle
        count := 0;                       --reset timer
      ELSIF(stretch = '0') THEN           --clock stretching from slave not detected
        count := count + 1;               --continue clock generation timing
      END IF;
      CASE count IS
        WHEN 0 TO divider-1 =>            --first 1/4 cycle of clocking
          scl_clk <= '0';
          data_clk <= '0';
        WHEN divider TO divider*2-1 =>    --second 1/4 cycle of clocking
          scl_clk <= '0';
          data_clk <= '1';
        WHEN divider*2 TO divider*3-1 =>  --third 1/4 cycle of clocking
          scl_clk <= '1';                 --release scl
          IF(scl = '0') THEN              --detect if slave is stretching clock
            stretch <= '1';
          ELSE
            stretch <= '0';
          END IF;
          data_clk <= '1';
        WHEN OTHERS =>                    --last 1/4 cycle of clocking
          scl_clk <= '1';
          data_clk <= '0';
      END CASE;
    END IF;
  END PROCESS;

  --state machine and writing to sda during scl low (data_clk rising edge)
  PROCESS(clk, reset_n)
  BEGIN
    IF(reset_n = '0') THEN                 --reset asserted
      state <= ready;                      --return to initial state
      busy <= '1';                         --indicate not available
      scl_ena <= '0';                      --sets scl high impedance
      sda_int <= '1';                      --sets sda high impedance
      ack_error <= '0';                    --clear acknowledge error flag
      bit_cnt <= 7;                        --restarts data bit counter
      data_rd <= "00000000";               --clear data read port
    ELSIF(clk'EVENT AND clk = '1') THEN
      IF(data_clk = '1' AND data_clk_prev = '0') THEN  --data clock rising edge
        CASE state IS
          WHEN ready =>                      --idle state
            IF(ena = '1') THEN               --transaction requested
              busy <= '1';                   --flag busy
              addr_rw <= addr & rw;          --collect requested slave address and command
              data_tx <= data_wr;            --collect requested data to write
              state <= start;                --go to start bit
            ELSE                             --remain idle
              busy <= '0';                   --unflag busy
              state <= ready;                --remain idle
            END IF;
          WHEN start =>                      --start bit of transaction
            busy <= '1';                     --resume busy if continuous mode
            sda_int <= addr_rw(bit_cnt);     --set first address bit to bus
            state <= command;                --go to command
          WHEN command =>                    --address and command byte of transaction
            IF(bit_cnt = 0) THEN             --command transmit finished
              sda_int <= '1';                --release sda for slave acknowledge
              bit_cnt <= 7;                  --reset bit counter for "byte" states
              state <= slv_ack1;             --go to slave acknowledge (command)
            ELSE                             --next clock cycle of command state
              bit_cnt <= bit_cnt - 1;        --keep track of transaction bits
              sda_int <= addr_rw(bit_cnt-1); --write address/command bit to bus
              state <= command;              --continue with command
            END IF;
          WHEN slv_ack1 =>                   --slave acknowledge bit (command)
            IF(addr_rw(0) = '0') THEN        --write command
              sda_int <= data_tx(bit_cnt);   --write first bit of data
              state <= wr;                   --go to write byte
            ELSE                             --read command
              sda_int <= '1';                --release sda from incoming data
              state <= rd;                   --go to read byte
            END IF;
          WHEN wr =>                         --write byte of transaction
            busy <= '1';                     --resume busy if continuous mode
            IF(bit_cnt = 0) THEN             --write byte transmit finished
              sda_int <= '1';                --release sda for slave acknowledge
              bit_cnt <= 7;                  --reset bit counter for "byte" states
              state <= slv_ack2;             --go to slave acknowledge (write)
            ELSE                             --next clock cycle of write state
              bit_cnt <= bit_cnt - 1;        --keep track of transaction bits
              sda_int <= data_tx(bit_cnt-1); --write next bit to bus
              state <= wr;                   --continue writing
            END IF;
          WHEN rd =>                         --read byte of transaction
            busy <= '1';                     --resume busy if continuous mode
            IF(bit_cnt = 0) THEN             --read byte receive finished
              IF(ena = '1' AND addr_rw = addr & rw) THEN  --continuing with another read at same address
                sda_int <= '0';              --acknowledge the byte has been received
              ELSE                           --stopping or continuing with a write
                sda_int <= '1';              --send a no-acknowledge (before stop or repeated start)
              END IF;
              bit_cnt <= 7;                  --reset bit counter for "byte" states
              data_rd <= data_rx;            --output received data
              state <= mstr_ack;             --go to master acknowledge
            ELSE                             --next clock cycle of read state
              bit_cnt <= bit_cnt - 1;        --keep track of transaction bits
              state <= rd;                   --continue reading
            END IF;
          WHEN slv_ack2 =>                   --slave acknowledge bit (write)
            IF(ena = '1') THEN               --continue transaction
              busy <= '0';                   --continue is accepted
              addr_rw <= addr & rw;          --collect requested slave address and command
              data_tx <= data_wr;            --collect requested data to write
              IF(addr_rw = addr & rw) THEN   --continue transaction with another write
                sda_int <= data_wr(bit_cnt); --write first bit of data
                state <= wr;                 --go to write byte
              ELSE                           --continue transaction with a read or new slave
                state <= start;              --go to repeated start
              END IF;
            ELSE                             --complete transaction
              state <= stop;                 --go to stop bit
            END IF;
          WHEN mstr_ack =>                   --master acknowledge bit after a read
            IF(ena = '1') THEN               --continue transaction
              busy <= '0';                   --continue is accepted and data received is available on bus
              addr_rw <= addr & rw;          --collect requested slave address and command
              data_tx <= data_wr;            --collect requested data to write
              IF(addr_rw = addr & rw) THEN   --continue transaction with another read
                sda_int <= '1';              --release sda from incoming data
                state <= rd;                 --go to read byte
              ELSE                           --continue transaction with a write or new slave
                state <= start;              --repeated start
              END IF;    
            ELSE                             --complete transaction
              state <= stop;                 --go to stop bit
            END IF;
          WHEN stop =>                       --stop bit of transaction
            busy <= '0';                     --unflag busy
            state <= ready;                  --go to idle state
        END CASE;    
      ELSIF(data_clk = '0' AND data_clk_prev = '1') THEN  --data clock falling edge
        CASE state IS
          WHEN start =>                  
            IF(scl_ena = '0') THEN                  --starting new transaction
              scl_ena <= '1';                       --enable scl output
              ack_error <= '0';                     --reset acknowledge error output
            END IF;
          WHEN slv_ack1 =>                          --receiving slave acknowledge (command)
            IF(sda /= '0' OR ack_error = '1') THEN  --no-acknowledge or previous no-acknowledge
              ack_error <= '1';                     --set error output if no-acknowledge
            END IF;
          WHEN rd =>                                --receiving slave data
            data_rx(bit_cnt) <= sda;                --receive current slave data bit
          WHEN slv_ack2 =>                          --receiving slave acknowledge (write)
            IF(sda /= '0' OR ack_error = '1') THEN  --no-acknowledge or previous no-acknowledge
              ack_error <= '1';                     --set error output if no-acknowledge
            END IF;
          WHEN stop =>
            scl_ena <= '0';                         --disable scl
          WHEN OTHERS =>
            NULL;
        END CASE;
      END IF;
    END IF;
  END PROCESS;  

  --set sda output
  WITH state SELECT
    sda_ena_n <= data_clk_prev WHEN start,     --generate start condition
                 NOT data_clk_prev WHEN stop,  --generate stop condition
                 sda_int WHEN OTHERS;          --set to internal sda signal    
      
  --set scl and sda outputs
  scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0') ELSE 'Z';
  sda <= '0' WHEN sda_ena_n = '0' ELSE 'Z';
  
END logic;

 

и пример его использования

Spoiler

WHEN get_data =>                               --state for conducting this transaction
  busy_prev <= i2c_busy;                       --capture the value of the previous i2c busy signal
  IF(busy_prev = '0' AND i2c_busy = '1') THEN  --i2c busy just went high
    busy_cnt := busy_cnt + 1;                    --counts the times busy has gone from low to high during transaction
  END IF;
  CASE busy_cnt IS                             --busy_cnt keeps track of which command we are on
    WHEN 0 =>                                  --no command latched in yet
      i2c_ena <= '1';                            --initiate the transaction
      i2c_addr <= slave_addr;                    --set the address of the slave
      i2c_rw <= '0';                             --command 1 is a write
      i2c_data_wr <= data_to_write;              --data to be written
    WHEN 1 =>                                  --1st busy high: command 1 latched, okay to issue command 2
      i2c_rw <= '1';                             --command 2 is a read (addr stays the same)
    WHEN 2 =>                                  --2nd busy high: command 2 latched, okay to issue command 3
      i2c_rw <= '0';                             --command 3 is a write
      i2c_data_wr <= new_data_to_write;          --data to be written
      IF(i2c_busy = '0') THEN                    --indicates data read in command 2 is ready
        data(15 DOWNTO 8) <= i2c_data_rd;          --retrieve data from command 2
      END IF;
    WHEN 3 =>                                  --3rd busy high: command 3 latched, okay to issue command 4
      i2c_rw <= '1';                             --command 4 is read (addr stays the same)
    WHEN 4 =>                                  --4th busy high: command 4 latched, ready to stop
      i2c_ena <= '0';                            --deassert enable to stop transaction after command 4
      IF(i2c_busy = '0') THEN                    --indicates data read in command 4 is ready
        data(7 DOWNTO 0) <= i2c_data_rd;           --retrieve data from command 4
        busy_cnt := 0;                             --reset busy_cnt for next transaction
        state <= home;                             --transaction complete, go to next state in design
      END IF;
    WHEN OTHERS => NULL;
  END CASE;

 

и я пытаюсь подстроить пример под мой чип, но что то не работает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так  может надо не подстраиваться под чужие проекты, а свой проект написать ?

И Вы моделирование запускали ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, Flip-fl0p said:

Так  может надо не подстраиваться под чужие проекты, а свой проект написать ?

И Вы моделирование запускали ?

зачем писать свой I2C когда есть крутой готовый.

У меня Сигнал тап - самое лучшее моделирование :).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

26 minutes ago, jenya7 said:

спасибо. слон он для меня слон, а для кого то Моська :)

Да уж - VHDL-ный слон большой и волосатый - мамонт настоящий :biggrin:

8 minutes ago, jenya7 said:

У меня Сигнал тап ... 

... и внутренности этого слона приходится рассматривать через ж...  маленькую дырочку сзади :wacko:

Удачи! Rob. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, RobFPGA said:

Приветствую!

Да уж - VHDL-ный слон большой и волосатый - мамонт настоящий :biggrin:

... и внутренности этого слона приходится рассматривать через ж...  маленькую дырочку сзади :wacko:

Удачи! Rob. 

загоните все сигналы на сигнал тап и рассматривайте через большую дырку. кто вам мешает? :)

sig_tap.thumb.png.5cf5474d4be8acee0f4979e190d4b0f9.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

15 minutes ago, jenya7 said:

загоните все сигналы на сигнал тап и рассматривайте через большую дырку. кто вам мешает? :)

В основном "запах" (usability) :bad: особенно у сигнал тап. 

Удачи! Rob.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...