jenya7 0 23 июля, 2019 Опубликовано 23 июля, 2019 (изменено) · Жалоба Есть пример использования драйвера 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 обновиться на следующем клоке? Изменено 23 июля, 2019 пользователем jenya7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба А Вы знаете в чем разница между variable и signal ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба Приветствую! 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 при этом нулевой). А как оно действительно нужно по алгоритму вам виднее. Так как нам не виден весь "слон" которого вы грызете. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба 1 hour ago, RobFPGA said: Приветствую! busy_cnt обновится сразу при инкременте. Но в 0 вы можете попасть если вдруг условие (busy_prev = '0' AND i2c_busy = '1') не будет выполнено при первом заходе в get_data (если конечно busy_cnt при этом нулевой). А как оно действительно нужно по алгоритму вам виднее. Так как нам не виден весь "слон" которого вы грызете. Удачи! 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; и я пытаюсь подстроить пример под мой чип, но что то не работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба Так может надо не подстраиваться под чужие проекты, а свой проект написать ? И Вы моделирование запускали ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба 2 hours ago, Flip-fl0p said: Так может надо не подстраиваться под чужие проекты, а свой проект написать ? И Вы моделирование запускали ? зачем писать свой I2C когда есть крутой готовый. У меня Сигнал тап - самое лучшее моделирование :). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба Приветствую! 26 minutes ago, jenya7 said: спасибо. слон он для меня слон, а для кого то Моська :) Да уж - VHDL-ный слон большой и волосатый - мамонт настоящий 8 minutes ago, jenya7 said: У меня Сигнал тап ... ... и внутренности этого слона приходится рассматривать через ж... маленькую дырочку сзади Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jenya7 0 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба 1 hour ago, RobFPGA said: Приветствую! Да уж - VHDL-ный слон большой и волосатый - мамонт настоящий ... и внутренности этого слона приходится рассматривать через ж... маленькую дырочку сзади Удачи! Rob. загоните все сигналы на сигнал тап и рассматривайте через большую дырку. кто вам мешает? :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 23 июля, 2019 Опубликовано 23 июля, 2019 · Жалоба Приветствую! 15 minutes ago, jenya7 said: загоните все сигналы на сигнал тап и рассматривайте через большую дырку. кто вам мешает? :) В основном "запах" (usability) особенно у сигнал тап. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться