VHDL: сигнал не может быть синтезирован, плохое синхронное описание

Я пытаюсь реализовать что-то вроде интерфейса SPI в VHDL для использования с FPGA.

Мое понимание VHDL ограничено, так как я использую его всего 2 дня, и я думаю, что не понял, как поток данных контролируется с помощью тактовых импульсов.

В настоящее время я понимаю, что вы можете рассматривать VHDL как процедурный язык программирования, если каждая инструкция, которую вы хотите выполнить в своей процедуре, выполняется последовательно, по одной инструкции за такт.

Это, наверное, звучит очень странно, так что это то, что у меня есть. Существует регистр SPI_REG, который содержит 8 бит данных, которые синхронизируются внешними часами. (Часы от главного к подчиненному устройству SPI. ПЛИС является подчиненным устройством. Главным устройством является Arduino, Raspberry Pi, мобильный телефон и т. Д.)

Есть последовательный порт входа и выхода, которые подключаются к главному устройству. (Линии данных MISO и MOSI.)

Есть счетчик, который считает количество часов. Он считает 8 тактов от 0 до 7, а затем переключается. Этот счетчик активирует флаг, когда ведущее устройство записало в регистр 8 бит данных.

Внутренние часы FPGA работают на гораздо более высокой скорости (50 МГц?), Чем внешние часы SPI. Каждый нарастающий фронт этих внутренних часов мы проверяем, установлен ли флаг, что означает, что было передано 8 бит данных, и FPGA должна скопировать эти данные, что-то с ними сделать и вернуть некоторые возвращаемые данные, прежде чем следующие часы SPI. Поэтому внутренние часы должны быть намного выше.

Этот процесс «перетасовки байтов» должен выполняться поэтапно.

  1. Байт копируется из регистра SPI в регистр.
  2. Байт возврата копируется в регистр SPI из еще одного регистра.

Итак, всего есть 3 регистра. Регистр SPI, регистр отправки и регистр приема.

Чтобы протестировать программу, я решил заполнить регистр отправки содержимым регистра приема с нулевым байтом XOR. «00000000» (Это еще ничего не «делает».)

Надеюсь, я достаточно хорошо это объяснил, вот код.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity interface is

    port
    (

        -- SPI
        SPI_MOSI: in std_logic;
        SPI_MISO: out std_logic;
        SPI_CLK: in std_logic;

        -- FPGA clocks
        SYSTEM_CLK: in std_logic;
    );

end interface;

architecture Behavioral of interface is

    -- SPI
    signal SPI_REG: std_logic_vector(7 downto 0) := (others => '0');
    signal SPI_BUFFER_OUT: std_logic_vector(7 downto 0) := (others => '0'); -- Holds most recent 8 bits transferred over SPI
    signal SPI_BUFFER_IN: std_logic_vector(7 downto 0) := (others => '0'); -- Holds next 8 bits to be transferred over SPI

    -- Shift register data
    --DATA_IN: in std_logic_vector(7 downto 0) := (others => '0');
    --DATA_OUT: out std_logic_vector(7 downto 0) := (others => '0');

begin

    -- SPI interface
    process(SYSTEM_CLK, SPI_CLK)--, AUDIO_CLK, BUSY)

        -- SPI interface
        variable spi_clk_count: integer := 0; -- count 8 data clocks
        variable system_clk_count: integer := 0; -- count system clocks for moving data out and in to spi register
        variable system_clk_flag: boolean := false;
        variable send_data_count: integer := 0;

        -- ADC control
        variable read_data_clock_count: integer := 0; -- count clock pulses for timing the reading of the ADC
        variable convst_flag: integer := 0; -- flag for the convst signal to the ADC

    begin

        -- SPI external clock
        if rising_edge(SPI_CLK) then
            -- Clock data out of serial_out (MISO or MOSI)

            if system_clk_flag = false then
                -- Complete transfers
                SPI_MISO <= SPI_REG(7);

                -- Clock data in spi_reg along 1 bit and feed in 1 bit from serial_in (MOSI or MISO)
                SPI_REG <= SPI_REG(6 downto 0) & SPI_MOSI; -- Concatinate bits
            end if;

            -- Check for full 8 bits
            if spi_clk_count = 7 then
                spi_clk_count := 0;

                -- Signal system clock to move byte out of and byte in to register
                if system_clk_flag = false then
                    -- Set buffer overrun error flag

                    -- Signal data to be clocked out and clocked in anyway
                    system_clk_flag := true;
                end if;
            else
                -- Increment spi clock counter
                spi_clk_count := spi_clk_count + 1;
            end if;

        end if;


        -- System internal clock
        if rising_edge(SYSTEM_CLK) then

            -- To test, return the XOR of the bits with zero (do nothing)
            -- Continue shuffling data if required
            if system_clk_count = 1 then
                -- Increment system_clock_count
                -- Change flag to "step 2"
                system_clk_count := 2;

                -- This is for debugging purposes
                SPI_BUFFER_IN <= SPI_BUFFER_OUT xor "00000000";


            elsif system_clk_count = 2 then
                -- Increment system_clock_count
                -- Change flag to "step 3"
                system_clk_count := 3;

                -- Move data from SPI_BUFFER_IN to register
                SPI_REG <= SPI_BUFFER_IN;

            elsif system_clk_count = 3 then
                -- Signal that we are done
                system_clk_flag := false;

                -- Reset clock count
                system_clk_count := 0;

            -- Check for signal for system clock to move data to and from SPI register
            elsif system_clk_flag = true then -- This must be done here because it is the lowest priority of the statements
                -- Signal for byte shuffling, clock data in and out
                system_clk_count := 1;

                -- Move data from SPI register to SPI_BUFFER_OUT register
                SPI_BUFFER_OUT <= SPI_REG;
            end if;

        end if;

end Behavioral;

У меня такое чувство, что то, как я это построил, совершенно неверно. Я могу нарисовать принципиальную схему, которая (я думаю) работала бы, но у меня серьезные проблемы с проектированием чего-либо с использованием VHDL.

Он не имеет синтаксических ошибок, но не может быть синтезирован. Любая помощь приветствуется.


person FreelanceConsultant    schedule 10.08.2014    source источник
comment
Я нашел решение, которое заключалось в использовании 4 флагов для обозначения того, когда 2 тактовых генератора необходимы для передачи некоторых данных, однако я до сих пор не уверен, даст ли это ожидаемые результаты.   -  person FreelanceConsultant    schedule 10.08.2014


Ответы (1)


Некоторые инструменты синтеза не поддерживают несколько часов в одном процессе. Исправление также указывало бы на то, что вы пытаетесь загрузить SPI_REG с использованием обоих часов.

В качестве предложения используйте процесс для каждого тактового домена, не используйте общие переменные, не используйте флаги. Единственное место, где вам нужно установить связь между доменами часов, - это SPI_BUFFER_OUT. SPI_BUFFER_IN загружается системными часами, _OUT - часами SPI.

Остерегайтесь метастабильности, вызванной рукопожатиями при пересечении границы часов. Должно быть только для системы, которая имеет более высокую тактовую частоту и / или работает асинхронно. Метастабильность невозможно смоделировать без временных моделей. Такие модели обычно просто жалуются

С асинхронным системным интерфейсом вы можете использовать одну защелку для буфера, загружаемого либо со стороны системы, либо со стороны SPI. Это потребует некоторого мультиплексирования входов и объединения двух разрешений с помощью ИЛИ.

И если ваши системные часы и часы SPI были получены из часов с более высокой скоростью и имели целочисленное отношение друг к другу, вы могли бы использовать включение часов и часы с более высокой скоростью.

person Community    schedule 11.08.2014