Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по передаче параметра в процедуру на VHDL
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Языки проектирования на ПЛИС (FPGA)
DSIoffe
Здравствуйте все!
Я пишу тестбенч для модуля I2C на VHDL. Делаю процедуру для передачи байта, сам байт передаю как параметр в эту процедуру.
Старший бит каждого байта формируется неправильно, остальные - правильно. Картинку прикладываю.
Вот код. В нём одна строка
wait for 1 ns;
закомментирована. Если её раскомментировать, то получается то, что мне надо. Можно бы и так оставить, но некрасиво.
Подскажите, пожалуйста, какую тонкость VHDL я не понимаю?
Заранее признателен.
CODE

library ieee;
use ieee.std_logic_1164.all;

entity myI2C_proc_tb is
end myI2C_proc_tb;

architecture behavioral of myI2C_proc_tb is

constant clk_period : time := 44 ns;
signal clk: std_logic := '0'; --тактовая частота модуля I2C_proc
signal Reset: std_logic := '0';
signal SCL: std_logic := '1';
signal SDA: std_logic := '1';
constant SCL_period: time := 4.35 us; --период SCLK
constant tri: time := SCL_period / 3.0; --треть периода SCK, время, за которое ничего не происходит
signal MyByte: std_logic_vector(7 downto 0);

--Объявления процедур
procedure i2c_start (signal mySCL: out std_logic; signal mySDA: out std_logic) is
begin
mySDA <= '1';
mySCL <= '1';
wait for tri;
mySDA <= '0';
wait for tri;
mySCL <= '0';
wait for tri;
end procedure i2c_start;

procedure i2c_stop (signal mySCL: out std_logic; signal mySDA: out std_logic) is
begin
mySDA <= '0';
mySCL <= '0';
wait for tri;
mySCL <= '1';
wait for tri;
mySDA <= '1';
wait for tri;
end procedure i2c_stop;

procedure i2c_writebyte (signal ySCL: out std_logic; signal ySDA: out std_logic;
signal ByteValue: in std_logic_vector(7 downto 0)) is
variable i: natural;
begin
--Передача байта:
i := 8;
-- wait for 1 ns;
while i > 0
loop
ySDA <= ByteValue(i - 1);
wait for tri;
ySCL <= '1';
wait for tri;
ySCL <= '0';
wait for tri;
i := i - 1;
end loop;
--Ожидание подтверждения:
ySDA <= 'Z';
wait for tri;
ySCL <= '1';
wait for tri;
ySCL <= '0';
wait for tri;
end procedure i2c_writebyte;

begin

--Тактовая частота:
clk <= not clk after (clk_period / 2.0 );

--Собственно моделирование
model_l:
process

begin
--Сброс схемы:
wait for clk_period * 2;
Reset <= '0';
--Посылка:
i2c_start(SCL, SDA);
MyByte(7 downto 1) <= B"0100001";
MyByte(0) <= '0';
i2c_writebyte(ySCL => SCL, ySDA => SDA, ByteValue => MyByte); --адресный байт
MyByte <= X"AA";
i2c_writebyte(SCL, SDA, MyByte);
MyByte <= X"AA";
i2c_writebyte(SCL, SDA, MyByte);
MyByte <= X"55";
i2c_writebyte(SCL, SDA, MyByte);
i2c_stop(SCL, SDA);

wait;
end process model_l;
end behavioral;
Flip-fl0p
Цитата(DSIoffe @ Aug 27 2018, 15:02) *

Я когда писал различные процедуры для тестирования I2С сделал чуть по-другому.
Я период клока SCL разделил на 4 части (удобно имитировать старт и стоп биты).
Ещё очень удобно имитировать подтяжку линий SCL и SDA при помощи сигнала типа "H" - благо VHDL умеет это.
И простой функцией мы преобразуем лог.1 в подтяжку:
Код
    -----------------------------------------------------------------------------------------------
    -- функция преборазования лог 1 в подтяжку
    function one_to_h (input : std_logic)     -- входные данные это обычный единичный бид
        return std_logic is                   -- возвращает такой-же бит
    begin
        if (input = '1') then                 -- если оказалось, что входной бит это 'h' состояние
            return 'h';                       -- вместо единички делаем подтяжку
        else                                  -- иначе
            return '0';                       -- возвращаем ноль
        end if;
    end one_to_h;


Вот так у меня выглядела процедура передачи байта от Master -> Slave:

Код
     procedure i2c_data_to_slave
        (
            signal slave_data_sig : in std_logic_vector(7 downto 0)
        )
        is
        begin
            for i in 7 downto 0 loop
                SDA <= one_to_h(slave_data_sig(i));
                SCL <= '0';
                wait for SCL_prd/4;            
                SDA <= one_to_h(slave_data_sig(i));
                SCL <= 'h';
                wait for SCL_prd/4;
                SDA <= one_to_h(slave_data_sig(i));
                SCL <= 'h';
                wait for SCL_prd/4;
                SDA <= one_to_h(slave_data_sig(i));
                SCL <= '0';
                wait for SCL_prd/4;
                SDA <= 'h';
                SCL <= 'h';
            end loop;
        end procedure i2c_data_to_slave;


Вот так вот у меня выглядит запись в Slave данных от 255 до 0 побайтно:
Код
   --=============================================================================
        -- рандомное чтение каждой ячекйи
        --=============================================================================
        wait for SCL_prd*10;
        testing  <= random_write;                                               -- включим состояние тестирования записи данных в память
        report lf & lf &"============== random write =================" & lf;  -- напишем что именно тестируем
        for i in 255 downto 0 loop
            i2c_start;                                                         -- старт условие
            i2c_addr_slave(slave_addr);                                        -- запрос адреса slave устройства
            direction_data(write_ram);                                         -- запрос на чтение
            i2c_slave_ack;                                                     -- подтверждение адреса слейва
            ram_addr_zero <= std_logic_vector(to_unsigned(i,8));
            i2c_data_to_slave(ram_addr_zero);                                  -- отправляем адрес ячейки с которой хотим работать (ячейка № 3)
            i2c_slave_ack;                                                     -- slave говорит ack придавив линию к земле  
            i2c_data_to_slave(ram_addr_zero);                                  -- записываем данные в память
            i2c_slave_ack;                                                     -- master говорит ack придавив линию к земле
            i2c_stop;                                                          -- стоп условие  
        end loop;


Если хотите могу поделиться тем, что у меня было сделано для тестирования I2C
Timmy
В качестве параметров вы используете сигналы, в которые перед вызовом процедуры выполнено отложенное присваивание. Первый по времени(старший) бит уходит ещё до того, как теневое значение сигнала синхронизировалось с видимым. Это можно пофиксить с помощью wait for 0s, тогда на временной диаграмме не будет видимых отличий, а лучше стараться вообще не использовать сигналы в тестбенчах без особой надобности, а если использовать, то без отложенных присваиваний.
DSIoffe
Цитата(Timmy @ Aug 28 2018, 12:22) *
В качестве параметров вы используете сигналы, в которые перед вызовом процедуры выполнено отложенное присваивание. Первый по времени(старший) бит уходит ещё до того, как теневое значение сигнала синхронизировалось с видимым. Это можно пофиксить с помощью wait for 0s, тогда на временной диаграмме не будет видимых отличий, а лучше стараться вообще не использовать сигналы в тестбенчах без особой надобности, а если использовать, то без отложенных присваиваний.

Спасибо, кажется, дошло. Сигнал может принять новое значение или после завершения всех происшествий, вызванных последним событием, или после оператора wait. У меня в месте вызова процедуры было присвоение значения байту, потом запуск процедуры, потом присвоение значения биту, и всё это время у сигнала нет повода завершить присвоения. То есть, реальное присвоение значения отправляемому байту произойдёт только после первого wait. Так?
wait for 0 s помогло.
А почему нельзя использовать сигналы в тестбенче? Как бы я мог иначе передавать в I2C разные байты через такую процедуру?

to Flip-fl0p
Спасибо, я тоже с удовольствием использую 'H'. Только ничего не преобразую, а в тексте описания модуля проекта пишу что-то вроде
if ipSCL = '0' then SCL <= '0'; else SCL <= '1'; end if; --Если ipSCL = 'H', то SCL <= 1
, где ipSCL - сигнал на выводе ПЛИС, а SCL - сигнал внутри неё, с которым работает начинка проекта.
Timmy
Цитата(DSIoffe @ Aug 28 2018, 17:15) *
Спасибо, кажется, дошло. Сигнал может принять новое значение или после завершения всех происшествий, вызванных последним событием, или после оператора wait. У меня в месте вызова процедуры было присвоение значения байту, потом запуск процедуры, потом присвоение значения биту, и всё это время у сигнала нет повода завершить присвоения. То есть, реальное присвоение значения отправляемому байту произойдёт только после первого wait. Так?
Всё так.
Цитата
wait for 0 s помогло.
А почему нельзя использовать сигналы в тестбенче? Как бы я мог иначе передавать в I2C разные байты через такую процедуру?

Сигналы можно использовать, но только там, где нужно. В данном случае, например, для SCL и SDA. А вот MyByte должен быть переменной. Кстати, переменные занимают меньше памяти и быстрее симулируются.

Я тоже иногда использовал wait for 0, не всё можно удобно сделать на переменных.
DSIoffe
Цитата(Timmy @ Aug 28 2018, 18:23) *
Всё так.
Сигналы можно использовать, но только там, где нужно. В данном случае, например, для SCL и SDA. А вот MyByte должен быть переменной. Кстати, переменные занимают меньше памяти и быстрее симулируются.
Я тоже иногда использовал wait for 0, не всё можно удобно сделать на переменных.

Большое спасибо. Я сделал MyByte переменной, теперь не надо wait for 0, чувствую себя культурным человеком sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.