Я пытаюсь реализовать что-то вроде интерфейса 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. Поэтому внутренние часы должны быть намного выше.
Этот процесс «перетасовки байтов» должен выполняться поэтапно.
- Байт копируется из регистра SPI в регистр.
- Байт возврата копируется в регистр 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.
Он не имеет синтаксических ошибок, но не может быть синтезирован. Любая помощь приветствуется.