Перейти к содержанию
    

SPI slave

Столкнулся с непонятной проблемой, выглядит так, что иногда на выходе получаю либо нули, либо мусор.

 

Подключил СигналТар, обнаружилась проблема в стейтмашине, из состояния NEXT_BIT она переходит в неопределенное когда все пины в 0 или поднимается пин WAIT_4_CLK и при этом NEXT_BIT остается поднятым и потом происходит переход в состояние WAIT_4_CS и данные портятся. Клок на spi 1Mhz, внутренний 50MHz.

 

Может кто то подсказать, в какой стороне копать проблему?

 

код компелируется в Quartus 11.0 под Cyclon lll

 

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity spi_slave is
   Port (  
       clk_50MHz	: in std_logic;      	                           -- internal clock

spi_cs	: in std_logic;		                              -- spi bus slave select line
       spi_clk	: in std_logic;		                              -- spi bus sck clock
       spi_mosi	: in std_logic;			                      -- spi bus mosi input
       spi_miso	: out std_logic;			                      -- spi bus miso output

status_reg		: in  std_logic_vector(15 downto 0);				-- parallel input status
rate_l_reg		: in  std_logic_vector(15 downto 0);				-- parallel input rate low bit
rate_h_reg		: in  std_logic_vector(15 downto 0);				-- parallel input rate hi bit
uscale_reg		: in  std_logic_vector(15 downto 0);				-- parallel input scale
temper_reg	: in  std_logic_vector(15 downto 0)				-- parallel input temperature
   );                      
end spi_slave;


architecture rtl of spi_slave is

type SPI_SM_Type is 
	(
	WAIT_4_CS,
	WAIT_4_CLK,
	SHIFT_BIT,
	NEXT_BIT
	);

signal spi_sm_state			: SPI_SM_Type := WAIT_4_CS;

signal shift_register_out		: std_logic_vector(111 downto 0);	

BEGIN

SPI_SM : process (clk_50MHz)

begin 

	if falling_edge (clk_50MHz) then

		case spi_sm_state is

			---------WAIT_4_CS--------
			when WAIT_4_CS =>

				if spi_cs = '0' then

					spi_sm_state <= WAIT_4_CLK;

					shift_register_out( 15 downto  0) <= "0000000000000000";
					shift_register_out( 31 downto 16) <= temper_reg;
					shift_register_out( 47 downto 32) <= uscale_reg;
					shift_register_out( 63 downto 48) <= rate_l_reg;
					shift_register_out( 79 downto 64) <= rate_h_reg;
					shift_register_out( 95 downto 80) <= status_reg;
					shift_register_out(111 downto 96) <= "0101010110101010";

				end if;

			-------------WAIT_4_CLK----------
			when WAIT_4_CLK =>

				if spi_cs = '0' then
					spi_miso	<= shift_register_out(111);

					if spi_clk = '1' then

						spi_sm_state <= SHIFT_BIT;

					end if;

				else
					spi_sm_state <= WAIT_4_CS;
				end if;


			-------------SHIFT_BIT----------
			when SHIFT_BIT =>
				if spi_cs = '0' then
					spi_sm_state <= NEXT_BIT;

					shift_register_out <= shift_register_out(110 downto 0) & '0';

				else
					spi_sm_state <= WAIT_4_CS;
				end if;

			-------------NEXT_BIT----------
			when NEXT_BIT =>
				if spi_cs = '0' then
					if spi_clk = '0' then
						spi_sm_state <= WAIT_4_CLK;
					end if;
				else
					spi_sm_state <= WAIT_4_CS;
				end if;
			-----------------------
			when others => null;
			-----------------------
		end case;

	end if;

end process SPI_SM;

end architecture rtl;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

поиском по форуму, за последний месяц темы две были.

 

асинхра у вас %)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Столкнулся с непонятной проблемой, выглядит так, что иногда на выходе получаю либо нули, либо мусор.

 

Подключил СигналТар, обнаружилась проблема в стейтмашине, из состояния NEXT_BIT она переходит в неопределенное когда все пины в 0 или поднимается пин WAIT_4_CLK и при этом NEXT_BIT остается поднятым и потом происходит переход в состояние WAIT_4_CS и данные портятся. Клок на spi 1Mhz, внутренний 50MHz.

 

Может кто то подсказать, в какой стороне копать проблему?

 

код компелируется в Quartus 11.0 под Cyclon lll

 

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity spi_slave is
   Port (  
       clk_50MHz	: in std_logic;      	                           -- internal clock

spi_cs	: in std_logic;		                              -- spi bus slave select line
       spi_clk	: in std_logic;		                              -- spi bus sck clock
       spi_mosi	: in std_logic;			                      -- spi bus mosi input
       spi_miso	: out std_logic;			                      -- spi bus miso output

status_reg		: in  std_logic_vector(15 downto 0);				-- parallel input status
rate_l_reg		: in  std_logic_vector(15 downto 0);				-- parallel input rate low bit
rate_h_reg		: in  std_logic_vector(15 downto 0);				-- parallel input rate hi bit
uscale_reg		: in  std_logic_vector(15 downto 0);				-- parallel input scale
temper_reg	: in  std_logic_vector(15 downto 0)				-- parallel input temperature
   );                      
end spi_slave;


architecture rtl of spi_slave is

type SPI_SM_Type is 
	(
	WAIT_4_CS,
	WAIT_4_CLK,
	SHIFT_BIT,
	NEXT_BIT
	);

signal spi_sm_state			: SPI_SM_Type := WAIT_4_CS;

signal shift_register_out		: std_logic_vector(111 downto 0);	

BEGIN

SPI_SM : process (clk_50MHz)

begin 

	if falling_edge (clk_50MHz) then

		case spi_sm_state is

			---------WAIT_4_CS--------
			when WAIT_4_CS =>

				if spi_cs = '0' then

					spi_sm_state <= WAIT_4_CLK;

					shift_register_out( 15 downto  0) <= "0000000000000000";
					shift_register_out( 31 downto 16) <= temper_reg;
					shift_register_out( 47 downto 32) <= uscale_reg;
					shift_register_out( 63 downto 48) <= rate_l_reg;
					shift_register_out( 79 downto 64) <= rate_h_reg;
					shift_register_out( 95 downto 80) <= status_reg;
					shift_register_out(111 downto 96) <= "0101010110101010";

				end if;

			-------------WAIT_4_CLK----------
			when WAIT_4_CLK =>

				if spi_cs = '0' then
					spi_miso	<= shift_register_out(111);

					if spi_clk = '1' then

						spi_sm_state <= SHIFT_BIT;

					end if;

				else
					spi_sm_state <= WAIT_4_CS;
				end if;


			-------------SHIFT_BIT----------
			when SHIFT_BIT =>
				if spi_cs = '0' then
					spi_sm_state <= NEXT_BIT;

					shift_register_out <= shift_register_out(110 downto 0) & '0';

				else
					spi_sm_state <= WAIT_4_CS;
				end if;

			-------------NEXT_BIT----------
			when NEXT_BIT =>
				if spi_cs = '0' then
					if spi_clk = '0' then
						spi_sm_state <= WAIT_4_CLK;
					end if;
				else
					spi_sm_state <= WAIT_4_CS;
				end if;
			-----------------------
			when others => null;
			-----------------------
		end case;

	end if;

end process SPI_SM;

end architecture rtl;

 

Прав ой как прав des00. Почитайте о синхронизации данных при их передаче между двумя разными клоковыми доменами, например на сайте уважаемого iosifk CDC

Изменено пользователем artix

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и кроме очевидного косяка с асинхронным управлением FSM тут ещё антиглитч напрашивается.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

всем спасибо за помощь, дело в том, что на входных сигналах перед блоком стоят триггеры на внутреннем клоке, хотя может конечно этого не достаточно.

 

на сигналтапе, внешний клок приходит ровно каждые 50 клоков внутреннего, без сбоев.

дата сигнал тоже поднимается без проблем, вовремя.

 

но вот раз в 10-30 передач, зависимости я не уловил, в момент перехода (переход в нужный момент) стейтмашина становится в два состояния одновременно (остатется поднятым бит предыдущего состояния и поднимается бит нового состояния) или опускает все состояния, соответственно передача сбивается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

всем спасибо за помощь, дело в том, что на входных сигналах перед блоком стоят триггеры на внутреннем клоке, хотя может конечно этого не достаточно.

 

дабы избежать метастабильного состояния их как минимум должно быть 2 :laughing:

причина такого поведения именно в метастабильности. К бабке не ходи :laughing:

ИМХО:На Вашем месте я бы завел spi_clk на PLL и на этой частоте принимал бы данные. Приняв,например, байт перекидывал бы в домен работающий на системном клоке. B)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

дабы избежать метастабильного состояния их как минимум должно быть 2 :laughing:

причина такого поведения именно в метастабильности. К бабке не ходи :laughing:

ИМХО:На Вашем месте я бы завел spi_clk на PLL и на этой частоте принимал бы данные. Приняв,например, байт перекидывал бы в домен работающий на системном клоке. B)

 

спасибо за совет, попробую реализовать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но вот раз в 10-30 передач

 

Свой тестбенч покажите.

Чтоб ясно было, чего Вы от схемы своей хотите.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity spi_slave is
Port ( 
clk_50MHz : in std_logic; -- internal clock

spi_cs : in std_logic; -- spi bus slave select line
spi_clk : in std_logic; -- spi bus sck clock
spi_miso : out std_logic; -- spi bus miso output

status_reg : in std_logic_vector(15 downto 0); -- parallel input status
rate_l_reg : in std_logic_vector(15 downto 0); -- parallel input rate low bit
rate_h_reg : in std_logic_vector(15 downto 0); -- parallel input rate hi bit
uscale_reg : in std_logic_vector(15 downto 0); -- parallel input scale
temper_reg : in std_logic_vector(15 downto 0) -- parallel input temperature
); 
end spi_slave;


architecture rtl of spi_slave is

signal                meta_cs : std_logic_vector(2 downto 0);
signal              meta_clk : std_logic_vector(4 downto 0);
signal shift_register_out : std_logic_vector(95 downto 0); 
signal     ena_cs, ena_clk : std_logic;


begin
process (clk_50MHz)
begin
if (clk_50MHz'event and clk_50MHz = '1') then

meta_cs <= meta_cs(1 downto 0) & spi_cs;
meta_clk <= meta_clk(3 downto 0) & spi_clk;

if (ena_cs = '1') then
--shift_register_out( 15 downto 0) <= "0000000000000000";
shift_register_out( 15 downto 0) <= temper_reg;
shift_register_out( 31 downto 16) <= uscale_reg;
shift_register_out( 47 downto 32) <= rate_l_reg;
shift_register_out( 63 downto 48) <= rate_h_reg;
shift_register_out( 79 downto 64) <= status_reg;
shift_register_out( 95 downto 80) <= "0101010110101010";
elsif (ena_clk = '1') then
shift_register_out <= shift_register_out(94 downto 0) & '0';
end if;

if (ena_clk = '1') then
spi_miso <= shift_register_out(95);
end if;

end if;
end process;

ena_cs <= not meta_cs(1) and meta_cs(2);
ena_clk <= not meta_clk(3) and meta_clk(4);
end architecture rtl;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

дабы избежать метастабильного состояния их как минимум должно быть 2 :laughing:

причина такого поведения именно в метастабильности. К бабке не ходи :laughing:

ИМХО:На Вашем месте я бы завел spi_clk на PLL и на этой частоте принимал бы данные. Приняв,например, байт перекидывал бы в домен работающий на системном клоке. B)

Плохой совет. SPI CLK - медленный клок, не факт что от него PLL заведётся. Кроме того в зависимости от источника этого клока он может иметь джиттер, глитчи и кучу других непонятных проблем.

Он может вообще пропасть - тогда PLLка тупо встанет и потом придётся долго плясать с бубном чтобы её завести.

Делайте как советует вам большинство : переводите все принятые с SPI сигналы в домен ваших внутренних клоков с помощью двойной защёлки (можно и больше сделать, попутно туда же запихать глитчедавилку). Вся схема - синхронная, работает от внутреннего клока. Фронты сигналов от SPI выделяются на этой же частоте, далее при необходимости подаются на CE входы разрешения триггеров

вашей FSM.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

c PLL не работает, наверное из-за того что SPI CLK появляется только на время передачи

 

а вот с двойным триггером все вроде стало на свои места, поставил на все входные spi сигналы, 10 Мб передались без единой ошибки.

 

всем большое спасибо за помощь.

 

еще только вопрос на счет гличедавилки, как ее реализовать и как правильно разместить?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

___Sergey___, выложи плиз конечный вариант.

Я сейчас только начинаю с ПЛИС работать и тоже нужно spi slave реализовать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

c PLL не работает, наверное из-за того что SPI CLK появляется только на время передачи

 

а вот с двойным триггером все вроде стало на свои места, поставил на все входные spi сигналы, 10 Мб передались без единой ошибки.

 

всем большое спасибо за помощь.

 

еще только вопрос на счет гличедавилки, как ее реализовать и как правильно разместить?

Ну например можно так : задвигаете входные данные в сдвиговый регистр, и выдаёте на выход 0 только тогда когда все биты этого регистра равны 0, точно также с единицами.

Во всех промежуточных состояниях на выход выдаётся то, что было ранее. Имеются некоторые противопоказания : глитчедавилка вносит задержку, это может пагубно повлиять если вам надо не только читать по SPI, но и писать.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

___Sergey___, выложи плиз конечный вариант.

Я сейчас только начинаю с ПЛИС работать и тоже нужно spi slave реализовать

 

то что я выкладывал и есть конечный вариант, только к нему на входные сигналы spi поставил по двойному триггеру.

и еще один ньюанс, девайс по запросу выдает значения сразу нескольких регистров и битовых поле, поэтому регистр такой длинный

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

то что я выкладывал и есть конечный вариант, только к нему на входные сигналы spi поставил по двойному триггеру.

и еще один ньюанс, девайс по запросу выдает значения сразу нескольких регистров и битовых поле, поэтому регистр такой длинный

так вроде здесь все описанное реализовано (код от sazh)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...