Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Подключение AD7478A к ПЛИС по SPI
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
Hit
Здравствуйте! Необходимо подключить АЦП AD7478А к ПЛИС. На вход ацп подается последовательность импульсов с частотой 4кГц, длительностью 1 мкс. Момент прихода импульса не известен. Т.е. необходимо поставить пороговое устройство(ПУ). Поясните, пожалуйста, как в этом случае необходимо считывать данные? На форуме нашел этот код. Правда он косячный. Необходимо сформировать cs-сигнал в момент прихода разрешающего сигнала с ПУ, и в этот же момент запустить тактовые импульсы, так? Просто нужно сформировать 12 импульсов,ацп выдаст по ним данные, которые придут в регистр?
Код
d:\zwork\tlc548(9)\top_lev.vhd
1 libraryIEEE;
2 useIEEE.STD_LOGIC_1164.ALL;
3 useIEEE.STD_LOGIC_ARITH.ALL;
4 useIEEE.STD_LOGIC_UNSIGNED.ALL;
5
6 entitytop_lev is
7 port(
8 clk : in std_logic; -- External clock
9 Data_adc: in std_logic; -- Data from ADC
10 cs : in std_logic; -- External ChipSelect
11 cs_adc : out std_logic; -- ChipSelect for ADC ==-Active Low-==
12 clk_adc : out std_logic; -- Clock for ADC
13 Data_out: out std_logic_vector(7 downto 0) -- Output Vector 8 bits
14 );
15 endtop_lev;
16
17 architectureBehavioral oftop_lev is
18
19 signalD_reg : std_logic_vector(7 downto 0);
20 signalcnt : std_logic_vector(2 downto 0);
21
22 begin
23
24 clk_adc <=clk;
25 cs_adc <=cs;
26
27 process(clk)
28 begin
29 if rising_edge(clk) then
30 ifcs ='0' then
31 D_reg <=D_reg(6 downto 0) &Data_adc;
32 --else
33 --D_reg <= (others => '0');
34 end if;
35 end if;
36 end process;
37
38 process(clk,cs)
39 begin
40 ifcs ='1' then
41 cnt <= (others =>'0');
42 elsif rising_edge(clk) then
43 cnt <=cnt +'1';
44 end if;
45 end process;
46
47 Data_out <=D_reg whencnt = "00000000";
48
49 endBehavioral;
50

Прикрепил временную диаграмму АЦП.
cnn2
В момент когда нужно считать данные с АЦП формируете временную диаграмму
по фронту CS получаете 8 бит данных
Hit
Парад глупых вопросов.
Когда высокий уровень на CS обязательно нSCLK переключать на высокий уровень ?
Когда происходит АЦ преобразование ?
Почему 4 zero? Почему не 3 ?
Data_out <=D_reg when cnt = "00000000"; - почему на выход передаются значения в момент, когда cnt = "00000000"?
Третье состояние после последнего бита, и даже если будут входные импульсы, оно все равно сохранится ?

При поступлении сигнала от ПУ, формируется CS, поступают тактовые импульсы. С каждым тактовым импульсом АЦП выдает одно значение. Оно поступает в сдвиговый регистр. В итоге после 12 импульсов в регистре 8 битное значение. Потом тактовые импульсы продолжают поступать, на на выходе АЦП 3 состояние. Потом ждем следующий сигнал от ПУ. И опять формируем CS длительностью 10 нс. И Все ?
Нужна помощь с кодом.
Схемотехническим проектированием занимался, а вот на VHDL писал только простенькие программы. Помогите с реализацией SPI. Простенькую структуру, а то в интернете нашел вот это, но тут трудновато для моего уровня:
Код
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY spi_master IS
  GENERIC(
    slaves  : INTEGER := 8;  --number of spi slaves
    d_width : INTEGER := 8); --data bus width
  PORT(
    clock   : IN     STD_LOGIC;                             --system clock
    reset_n : IN     STD_LOGIC;                             --asynchronous reset
    enable  : IN     STD_LOGIC;                             --initiate transaction
    cpol    : IN     STD_LOGIC;                             --spi clock polarity
    cpha    : IN     STD_LOGIC;                             --spi clock phase
    cont    : IN     STD_LOGIC;                             --continuous mode command
    clk_div : IN     INTEGER;                               --system clock cycles per 1/2 period of sclk
    addr    : IN     INTEGER;                               --address of slave
    tx_data : IN     STD_LOGIC_VECTOR(d_width-1 DOWNTO 0);  --data to transmit
    miso    : IN     STD_LOGIC;                             --master in, slave out
    sclk    : BUFFER STD_LOGIC;                             --spi clock
    ss_n    : BUFFER STD_LOGIC_VECTOR(slaves-1 DOWNTO 0);   --slave select
    mosi    : OUT    STD_LOGIC;                             --master out, slave in
    busy    : OUT    STD_LOGIC;                             --busy / data ready signal
    rx_data : OUT    STD_LOGIC_VECTOR(d_width-1 DOWNTO 0)); --data received
END spi_master;

ARCHITECTURE logic OF spi_master IS
  TYPE machine IS(ready, execute);                           --state machine data type
  SIGNAL state       : machine;                              --current state
  SIGNAL slave       : INTEGER;                              --slave selected for current transaction
  SIGNAL clk_ratio   : INTEGER;                              --current clk_div
  SIGNAL count       : INTEGER;                              --counter to trigger sclk from system clock
  SIGNAL clk_toggles : INTEGER RANGE 0 TO d_width*2 + 1;     --count spi clock toggles
  SIGNAL assert_data : STD_LOGIC;                            --'1' is tx sclk toggle, '0' is rx sclk toggle
  SIGNAL continue    : STD_LOGIC;                            --flag to continue transaction
  SIGNAL rx_buffer   : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --receive data buffer
  SIGNAL tx_buffer   : STD_LOGIC_VECTOR(d_width-1 DOWNTO 0); --transmit data buffer
  SIGNAL last_bit_rx : INTEGER RANGE 0 TO d_width*2;         --last rx data bit location
BEGIN
  PROCESS(clock, reset_n)
  BEGIN

    IF(reset_n = '0') THEN        --reset system
      busy <= '1';                --set busy signal
      ss_n <= (OTHERS => '1');    --deassert all slave select lines
      mosi <= 'Z';                --set master out to high impedance
      rx_data <= (OTHERS => '0'); --clear receive data port
      state <= ready;             --go to ready state when reset is exited

    ELSIF(clock'EVENT AND clock = '1') THEN
      CASE state IS               --state machine

        WHEN ready =>
          busy <= '0';             --clock out not busy signal
          ss_n <= (OTHERS => '1'); --set all slave select outputs high
          mosi <= 'Z';             --set mosi output high impedance
          continue <= '0';         --clear continue flag

          --user input to initiate transaction
          IF(enable = '1') THEN      
            busy <= '1';             --set busy signal
            IF(addr < slaves) THEN   --check for valid slave address
              slave <= addr;         --clock in current slave selection if valid
            ELSE
              slave <= 0;            --set to first slave if not valid
            END IF;
            IF(clk_div = 0) THEN     --check for valid spi speed
              clk_ratio <= 1;        --set to maximum speed if zero
              count <= 1;            --initiate system-to-spi clock counter
            ELSE
              clk_ratio <= clk_div;  --set to input selection if valid
              count <= clk_div;      --initiate system-to-spi clock counter
            END IF;
            sclk <= cpol;            --set spi clock polarity
            assert_data <= NOT cpha; --set spi clock phase
            tx_buffer <= tx_data;    --clock in data for transmit into buffer
            clk_toggles <= 0;        --initiate clock toggle counter
            last_bit_rx <= d_width*2 + conv_integer(cpha) - 1; --set last rx data bit
            state <= execute;        --proceed to execute state
          ELSE
            state <= ready;          --remain in ready state
          END IF;

        WHEN execute =>
          busy <= '1';        --set busy signal
          ss_n(slave) <= '0'; --set proper slave select output
          
          --system clock to sclk ratio is met
          IF(count = clk_ratio) THEN        
            count <= 1;                     --reset system-to-spi clock counter
            assert_data <= NOT assert_data; --switch transmit/receive indicator
            clk_toggles <= clk_toggles + 1; --increment spi clock toggles counter
            
            --spi clock toggle needed
            IF(clk_toggles <= d_width*2 AND ss_n(slave) = '0') THEN
              sclk <= NOT sclk; --toggle spi clock
            END IF;
            
            --receive spi clock toggle
            IF(assert_data = '0' AND clk_toggles < last_bit_rx + 1 AND ss_n(slave) = '0') THEN
              rx_buffer <= rx_buffer(d_width-2 DOWNTO 0) & miso; --shift in received bit
            END IF;
            
            --transmit spi clock toggle
            IF(assert_data = '1' AND clk_toggles < last_bit_rx) THEN
              mosi <= tx_buffer(d_width-1);                     --clock out data bit
              tx_buffer <= tx_buffer(d_width-2 DOWNTO 0) & '0'; --shift data transmit buffer
            END IF;
            
            --last data receive, but continue
            IF(clk_toggles = last_bit_rx AND cont = '1') THEN
              tx_buffer <= tx_data;                       --reload transmit buffer
              clk_toggles <= last_bit_rx - d_width*2 + 1; --reset spi clock toggle counter
              continue <= '1';                            --set continue flag
            END IF;
            
            --normal end of transaction, but continue
            IF(continue = '1') THEN  
              continue <= '0';      --clear continue flag
              busy <= '0';          --clock out signal that first receive data is ready
              rx_data <= rx_buffer; --clock out received data to output port    
            END IF;
            
            --end of transaction
            IF((clk_toggles = d_width*2 + 1) AND cont = '0') THEN  
              busy <= '0';             --clock out not busy signal
              ss_n <= (OTHERS => '1'); --set all slave selects high
              mosi <= 'Z';             --set mosi output high impedance
              rx_data <= rx_buffer;    --clock out received data to output port
              state <= ready;          --return to ready state
            ELSE                       --not end of transaction
              state <= execute;        --remain in execute state
            END IF;
          
          ELSE              --system clock to sclk ratio not met
            count <= count + 1; --increment counter
            state <= execute;   --remain in execute state
          END IF;

      END CASE;
    END IF;
  END PROCESS;
END logic;
cnn2
1. необязательно, на временной диаграмме это отмечено пунктиром, но
обязательно перед спадом CS установить SCLK в 1, поэтому проще всего держать SCLK в 1
в неактивном состоянии
2. The CS signal initiates the data transfer and conversion process.
The falling edge of CS puts the track-and-hold into hold mode
and takes the bus out of three-state
преобразование начинается по спаду CS
3. думается что нули выдаются пока идет преобразование

минимум CS 10 ns, более важно значение tQUIET минимум 50 ns
Iptash
Все же просто.
Ваш цикл : CS в 1 SCLK в 1, CS уст. в 0 выжидается время мин. t2 после чего вы выдаете серию 12 импульсов SCLK со скваженностью мин. указанные в даташит и тем самым загружаете в ваш входной регистр данные АЦП SDATA. После чего у вас SCLK должен находится в 1 потом CS также в 1 и выжидаете время tQUIET.
Первые 4 нулевых бита можно наверное использовать для проверки на 0. Если не 0, то значит есть помехи. И вообще у вас могут записываться не корректные данные
во входной регистр если не принять меры по "очистке " входного сигнала.
Hit
Спасибо)
Hit
Помогите. Голова уже не соображает. Вот диаграмма. Код.
CODE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity SPI_Master is
Generic ( Quarz_Taktfrequenz : integer := 96000000;
SPI_Taktfrequenz : integer := 48000000;
Laenge : integer := 16
);
Port (
RX_Data : out STD_LOGIC_VECTOR (Laenge-1 downto 0);
MISO : in STD_LOGIC;
SCLK : out STD_LOGIC;
SS : out STD_LOGIC;
TX_Start : in STD_LOGIC;
TX_Done : out STD_LOGIC;
clk : in STD_LOGIC
);
end SPI_Master;

architecture Behavioral of SPI_Master is
signal delay : integer range 0 to (Quarz_Taktfrequenz/(2*SPI_Taktfrequenz));
constant clock_delay : integer := (Quarz_Taktfrequenz/(4*SPI_Taktfrequenz));

type spitx_states is (spi_stx,spi_txactive,spi_etx);
signal spitxstate : spitx_states := spi_stx;

signal spiclk : std_logic;
signal spiclklast: std_logic;

signal bitcounter : integer range 0 to Laenge; -- wenn bitcounter = Laenge --> alle Bits uebertragen
signal rx_reg : std_logic_vector(Laenge-1 downto 0) := (others=>'0');

begin

process begin
wait until falling_edge(CLK);
if(delay>0) then delay <= delay-1;
else delay <= clock_delay;
end if;
spiclklast <= spiclk;

case spitxstate is
when spi_stx =>
SS <= '1';
TX_Done <= '0';
bitcounter <= Laenge;
spiclk <= '1';
if(TX_Start = '1') then
spitxstate <= spi_txactive;
SS <= '0';
delay <= clock_delay;
end if;

when spi_txactive =>
if (delay=0) then
spiclk <= not spiclk;
if (bitcounter=0) then
spiclk <= '1';
spitxstate <= spi_etx;
end if;
if(spiclk='1') then
bitcounter <= bitcounter-1;
end if;
end if;

when spi_etx =>
SS <= '1';
TX_Done <= '1';
if(TX_Start = '0') then
spitxstate <= spi_stx;
end if;
end case;
end process;

process begin
wait until falling_edge(CLK);
if (spiclk='1' and spiclklast='0' ) then
rx_reg <= rx_reg(rx_reg'left-1 downto 0) & MISO;
end if;
end process;


SCLK <= spiclk;
RX_Data <= rx_reg;

end Behavioral;


И тестБенч.
CODE
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb_SPI_Master_vhd IS
END tb_SPI_Master_vhd;

ARCHITECTURE behavior OF tb_SPI_Master_vhd IS

COMPONENT SPI_Master
Port ( RX_Data : out STD_LOGIC_VECTOR (15 downto 0);
MISO : in STD_LOGIC;
SCLK : out STD_LOGIC;
SS : out STD_LOGIC;
TX_Start : in STD_LOGIC;
TX_Done : out STD_LOGIC;
clk : in STD_LOGIC
);
END COMPONENT;

SIGNAL MISO : std_logic := '0';
SIGNAL TX_Start : std_logic := '0';
SIGNAL clk : std_logic := '0';



SIGNAL RX_Data : std_logic_vector(15 downto 0);
SIGNAL SCLK : std_logic;
SIGNAL SS : std_logic;
SIGNAL TX_Done : std_logic;

SIGNAL rxsrslave : std_logic_vector(15 downto 0) := x"0000";

BEGIN

uut: SPI_Master PORT MAP(
RX_Data => RX_Data,
MISO => MISO,
SCLK => SCLK,
SS => SS,
TX_Start => TX_Start,
TX_Done => TX_Done,
clk => clk
);

clk <= not clk after 5.2 ns; -- 96 MHz

process (sclk) begin
if (falling_edge(SCLK)) then
rxsrslave <= rxsrslave(14 downto 0) & MISO;
end if;
end process;




b : PROCESS BEGIN

wait for 3035 ns;
MISO<='1';

wait for 106688 ns;
MISO<='0';
wait;
END PROCESS;



tb : PROCESS BEGIN

wait for 3 us;
TX_Start <= '1';

wait until TX_Done='1';
TX_Start <= '0';
wait for 100000 ns;


wait for 3 us;
TX_Start <= '1';

wait until TX_Done='1';
TX_Start <= '0';
wait for 100000 ns;


wait for 3 us;
TX_Start <= '1';

wait until TX_Done='1';
TX_Start <= '0';
wait;
END PROCESS;

END;


В Rx_date записывается лишнее значение. rxrslave прописан в тестбенче, он тактируется SCLK , поэтому там правильно записывается(по заднему фронту). Rx_date тактируется clk, запись туда производится при spiclk='1' and spiclklast='0' . И в самом конце он производит лишнюю запись. Как исправить ? Никак не соображу что понаделал.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.