|
|
|
Вопрос по передаче параметра в процедуру на VHDL |
|
|
|
Aug 27 2018, 12:02
|
Дима
Группа: Свой
Сообщений: 1 683
Регистрация: 15-12-04
Из: Санкт-Петербург
Пользователь №: 1 486
|
Здравствуйте все! Я пишу тестбенч для модуля 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;
Эскизы прикрепленных изображений
--------------------
|
|
|
|
|
Aug 28 2018, 04:34
|
В поисках себя...
Группа: Свой
Сообщений: 729
Регистрация: 11-06-13
Из: Санкт-Петербург
Пользователь №: 77 140
|
Цитата(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
|
|
|
|
|
Aug 28 2018, 14:15
|
Дима
Группа: Свой
Сообщений: 1 683
Регистрация: 15-12-04
Из: Санкт-Петербург
Пользователь №: 1 486
|
Цитата(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 - сигнал внутри неё, с которым работает начинка проекта.
--------------------
|
|
|
|
|
Aug 28 2018, 15:23
|
Знающий
Группа: Участник
Сообщений: 835
Регистрация: 9-08-08
Из: Санкт-Петербург
Пользователь №: 39 515
|
Цитата(DSIoffe @ Aug 28 2018, 17:15) Спасибо, кажется, дошло. Сигнал может принять новое значение или после завершения всех происшествий, вызванных последним событием, или после оператора wait. У меня в месте вызова процедуры было присвоение значения байту, потом запуск процедуры, потом присвоение значения биту, и всё это время у сигнала нет повода завершить присвоения. То есть, реальное присвоение значения отправляемому байту произойдёт только после первого wait. Так? Всё так. Цитата wait for 0 s помогло. А почему нельзя использовать сигналы в тестбенче? Как бы я мог иначе передавать в I2C разные байты через такую процедуру? Сигналы можно использовать, но только там, где нужно. В данном случае, например, для SCL и SDA. А вот MyByte должен быть переменной. Кстати, переменные занимают меньше памяти и быстрее симулируются. Я тоже иногда использовал wait for 0, не всё можно удобно сделать на переменных.
|
|
|
|
|
Aug 29 2018, 15:13
|
Дима
Группа: Свой
Сообщений: 1 683
Регистрация: 15-12-04
Из: Санкт-Петербург
Пользователь №: 1 486
|
Цитата(Timmy @ Aug 28 2018, 18:23) Всё так. Сигналы можно использовать, но только там, где нужно. В данном случае, например, для SCL и SDA. А вот MyByte должен быть переменной. Кстати, переменные занимают меньше памяти и быстрее симулируются. Я тоже иногда использовал wait for 0, не всё можно удобно сделать на переменных. Большое спасибо. Я сделал MyByte переменной, теперь не надо wait for 0, чувствую себя культурным человеком
--------------------
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|