Jump to content

    

Скомутировать два вывода наружу.

Recommended Posts

jenya7

Есть два мастер SPI которые пользуются общими пинами в TOP ENTITY

NewProject-1.png.cb82349ff41fe9d82ec054097aee86d5.png

Я могу сделать так

entity TOP is
port
(
    ADC_SS1    : out std_logic;
    ADC_SS2    : out std_logic;
    ADCS_SCLK  : out std_logic;
    ADCS_MOSI  : out std_logic;
    ADCS_MISO  : in std_logic 
);
end TOP;

U_ADC_1 : ADC 
port map
(	 
    CS    => ADC_SS1, 
    SCLK  => s_adc1_clk,
    MOSI  => s_mosi1_clk,
    MISO  => ADCS_MISO,	 
);

U_ADC_2 : ADC 
port map
(
    CS    => ADC_SS2, 
    SCLK  => s_adc2_clk,
    MOSI  => s_mosi2_clk,
    MISO  => ADCS_MISO
);


ADCS_SCLK <= s_adc1_clk or s_adc2_clk;
ADCS_MOSI <= s_mosi1_clk or s_mosi2_clk;

Но вот гложет меня сомнение правильно комутирировать с OR или есть более правильное решение?

Share this post


Link to post
Share on other sites

Flip-fl0p
Только что, jenya7 сказал:

Есть два мастер SPI которые пользуются общими пинами в TOP ENTITY

NewProject-1.png.cb82349ff41fe9d82ec054097aee86d5.png

Я могу сделать так

entity TOP is
port
(
    ADC_SS1    : out std_logic;
    ADC_SS2    : out std_logic;
    ADCS_SCLK  : out std_logic;
    ADCS_MOSI  : out std_logic;
    ADCS_MISO  : in std_logic 
);
end TOP;

U_ADC_1 : ADC 
port map
(	 
    CS    => ADC_SS1, 
    SCLK  => s_adc1_clk,
    MOSI  => s_mosi1_clk,
    MISO  => ADCS_MISO,	 
);

U_ADC_2 : ADC 
port map
(
    CS    => ADC_SS2, 
    SCLK  => s_adc2_clk,
    MOSI  => s_mosi2_clk,
    MISO  => ADCS_MISO
);


ADCS_SCLK <= s_adc1_clk or s_adc2_clk;
ADCS_MOSI <= s_mosi1_clk or s_mosi2_clk;

Но вот гложет меня сомнение правильно комутирировать с OR или есть более правильное решение?

Арбитр доступа которой рулит коллизиями, когда оба мастера хотят поиметь слейва.

Share this post


Link to post
Share on other sites

jenya7
9 minutes ago, Flip-fl0p said:

Арбитр доступа которой рулит коллизиями, когда оба мастера хотят поиметь слейва.

а как его сделать правильно?

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

Edited by jenya7

Share this post


Link to post
Share on other sites

des00
35 minutes ago, jenya7 said:

Но вот гложет меня сомнение правильно комутирировать с OR или есть более правильное решение?

AND-OR мультиплексор вещь обычная и довольно часто используемая, но, т.к. тут есть два канала управления (которые маски), требуется обеспечить режим, чтобы оба мастера не могли быть активными. Если вы делаете это на административном уровне и у вас всегда, у выключенного мастера сигналы падают в 0, то вы все сделали верно. 

Share this post


Link to post
Share on other sites

jenya7
16 minutes ago, des00 said:

AND-OR мультиплексор вещь обычная и довольно часто используемая, но, т.к. тут есть два канала управления (которые маски), требуется обеспечить режим, что оба мастера не могут быть активными. 

что то вроде?

chip_sel <= ADC_SS2 & ADC_SS1;

case chip_sel is
  when "01" => ADCS_SCLK <= s_adc1_clk;
  when "10" => ADCS_SCLK <= s_adc2_clk;
  default =>
end case;  

 

Edited by jenya7

Share this post


Link to post
Share on other sites

des00
35 minutes ago, jenya7 said:

что то вроде?

chip_sel <= ADC_SS2 & ADC_SS1;

case chip_sel is
  when "01" => ADCS_SCLK <= s_adc1_clk;
  when "10" => ADCS_SCLK <= s_adc2_clk;
  default =>
end case;  

 

ADCS_SCLK <= (s_adc1_clk and adc_ss1) or (s_adc2_clk and adc_ss2); - ложится в один LUT4, за это, в свое время, эту схему любили для широких мультиплексоров. 

(adc_ss1 =1) & (adc_ss2 = 1) естественно запрещенная ситуация. 

Если маски есть у вас внутри блоков ADC, то снаружи достаточно просто or 

Share this post


Link to post
Share on other sites

jenya7
4 minutes ago, des00 said:

ADCS_SCLK <= (s_adc1_clk and adc_ss1) or (s_adc2_clk and adc_ss2); - ложится в один LUT4, за это, в свое время, эту схему любили для широких мультиплексоров. 

(adc_ss1 =1) & (adc_ss2 = 1) естественно запрещенная ситуация. 

Если маски есть у вас внутри блоков ADC, то снаружи достаточно просто or 

тогда наверно так?

ADCS_SCLK <= (s_adc1_clk and not adc_ss1) or (not s_adc2_clk and adc_ss2);

Share this post


Link to post
Share on other sites

des00
2 minutes ago, jenya7 said:

тогда наверно так?

ADCS_SCLK <= (s_adc1_clk and not adc_ss1) or (not s_adc2_clk and adc_ss2);

по управлению вам виднее какой у вас уровень активный) смысл я думаю вы поняли) 

но вот зачем инвертировать вторую тактовую я не понял) 

Share this post


Link to post
Share on other sites

jenya7
1 minute ago, des00 said:

вам виднее какой у вас уровень активный) смысл я думаю вы поняли) 

но это всё равно не блокирует. я же могу оба CS опустить.

Share this post


Link to post
Share on other sites

des00
10 minutes ago, jenya7 said:

но это всё равно не блокирует. я же могу оба CS опустить.

эмм. Вы вообще не читаете мои ответы? 

Quote

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

(adc_ss1 =1) & (adc_ss2 = 1) естественно запрещенная ситуация. 

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

UPD. Именно арбитр включения модуля, а не мультиплексирования транзакции SPI. Т.к. SPI транзакцию рвать нельзя. Самое простое сделать сигнал Enable в модулях и уже ими управлять исходя из поступающих запросов на доступ к SPI. А для мультиплексирования, сделать все сигналы в пассивном состоянии 0. на верхнем уровне простой OR.

Share this post


Link to post
Share on other sites

jenya7

спасибо. буду думать над арбитром.

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

Edited by jenya7

Share this post


Link to post
Share on other sites

des00
5 minutes ago, jenya7 said:

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

я бы сделал один SPI модуль и к нему приделал многоканальный арбитр доступа. Ну а сами источники транзакций пусть работают по простому valid & ready интерфейсу) А если ready не подразумевается в источниках транзакций, сами транзакции редкие, а запрос - импульс длительностью 1 такт, то просто захватываете его, на арбитр, как он получил доступ, сбрасываете его.  

Share this post


Link to post
Share on other sites

jenya7
1 hour ago, des00 said:

я бы сделал один SPI модуль и к нему приделал многоканальный арбитр доступа. Ну а сами источники транзакций пусть работают по простому valid & ready интерфейсу) А если ready не подразумевается в источниках транзакций, сами транзакции редкие, а запрос - импульс длительностью 1 такт, то просто захватываете его, на арбитр, как он получил доступ, сбрасываете его.  

спасибо. это идея. всё придется переделывать. :)

 

ну вот как то так получается

Spoiler
entity TOP is
port
(
     TOP_CLK    : in std_logic;
	 TOP_RST    : in std_logic := '0';
	  
	 ----------ADC SPI-----------
	 ADC_SS1    : out std_logic;
	 ADC_SS2    : out std_logic;
	 ADC_SS3    : out std_logic;
	 ADC_SS4    : out std_logic;
	 
	 ADCS_SCLK  : out std_logic;
	 ADCS_MOSI  : out std_logic;
	 ADCS_MISO  : in std_logic;
	 
	 LED_TEST   : out std_logic
);
end TOP;

architecture behavior of TOP is

  ------------------ADC---------------------------------
signal s_adc_cs_mask : std_logic_vector(3 downto 0);

signal s_adc_trig : std_logic;
signal s_adc_chan : std_logic_vector(2 downto 0);
signal s_adc_val  : std_logic_vector(15 downto 0);
signal s_rd_data : std_logic_vector(15 downto 0); 
signal s_wr_data : std_logic_vector(15 downto 0); 
signal s_wr_start_trig : std_logic;
signal s_wr_done : std_logic;
signal s_wr_done_clr : std_logic;

signal s_adc1_cs : std_logic;
signal s_adc1_trig : std_logic;
signal s_adc1_chan : std_logic_vector(2 downto 0);
signal s_adc1_val  : std_logic_vector(15 downto 0);
signal s_rd_data1 : std_logic_vector(15 downto 0); 
signal s_wr_data1 : std_logic_vector(15 downto 0); 
signal s_wr_start_trig1 : std_logic;
signal s_wr_done1 : std_logic;
signal s_wr_done_clr1 : std_logic;

signal s_adc2_cs : std_logic;
signal s_adc2_trig : std_logic;
signal s_adc2_chan : std_logic_vector(2 downto 0);
signal s_adc2_val  : std_logic_vector(15 downto 0);
signal s_rd_data2 : std_logic_vector(15 downto 0); 
signal s_wr_data2 : std_logic_vector(15 downto 0); 
signal s_wr_start_trig2 : std_logic;
signal s_wr_done2 : std_logic;
signal s_wr_done_clr2 : std_logic;

signal s_adc3_cs : std_logic;
signal s_adc3_trig : std_logic;
signal s_adc3_chan : std_logic_vector(2 downto 0);
signal s_adc3_val  : std_logic_vector(15 downto 0);
signal s_rd_data3 : std_logic_vector(15 downto 0); 
signal s_wr_data3 : std_logic_vector(15 downto 0); 
signal s_wr_start_trig3 : std_logic;
signal s_wr_done3 : std_logic;
signal s_wr_done_clr3 : std_logic;

signal s_adc4_cs : std_logic;
signal s_adc4_trig : std_logic;
signal s_adc4_chan : std_logic_vector(2 downto 0);
signal s_adc4_val  : std_logic_vector(15 downto 0);
signal s_rd_data4 : std_logic_vector(15 downto 0); 
signal s_wr_data4 : std_logic_vector(15 downto 0); 
signal s_wr_start_trig4 : std_logic;
signal s_wr_done4 : std_logic;
signal s_wr_done_clr4 : std_logic;

begin
  
s_adc_cs_mask <= s_adc4_cs & s_adc3_cs & s_adc2_cs & s_adc1_cs;

U_ADC_SPI_MASTER : GENERIC_SPI 
port map
(	 
    RST	    => '0',
    CLK     => TOP_CLK,
	 
    SPI_nCS       => '0',
    SPI_CLK       => ADCS_SCLK,
    SPI_MasterOut => ADCS_MOSI,
    SPI_MasterIn  => ADCS_MISO, 
		
    SPI_CTRL_REG   => "000", --bit0  = CPHA bit1  = CPOL bit2 = MSBnLSB_FIRST
    SPI_BAUD_DIV   => X"000C",  --120Mhz
    SPI_DATA_LENGTH   => '1', --0 = length of 8 bits --1 = 16 bit

    SPI_Wr_Data       => s_wr_data,
    SPI_Rd_Data       => s_rd_data, 
    SPI_Wr_Start_Trig => s_wr_start_trig,  
		
    SPI_Rd_Start_Trig  => '0',   
    SPI_Data_Ready	   => open,
    SPI_Data_Ready_Clear => '0', 
		
    SPI_Wr_DONE		  => s_wr_done,
    SPI_Wr_DONE_Clear => s_wr_done_clr,
		
    SPI_WR_En		 => open,		
    SPI_Data_Count   => open	                                           
);	

U_ADC_1 : ADC 
port map
(
    ADC_CLK  => TOP_CLK,
    ADC_RST  => TOP_RST,
	 
     CS          => s_adc1_cs, 
	 WR_DONE_CLR => s_wr_done_clr1,
	 WR_START    => s_wr_start_trig1, 
	 WR_DONE     => s_wr_done1,
	 
	 WR_DATA  => s_wr_data1,
	 RD_DATA  => s_rd_data1, 
	 
	 TRIG     => s_adc1_trig,
	 
	 CHAN     => s_adc_chan,
	
	 ADC_VAL  => s_adc1_val
);

U_ADC_2 : ADC 
port map
(
    ADC_CLK  => TOP_CLK,
	ADC_RST  => TOP_RST,
	 
	 CS           => s_adc2_cs,
	 WR_DONE_CLR  => s_wr_done_clr2,
	 WR_START     => s_wr_start_trig2, 
	 WR_DONE      => s_wr_done2,
	 
	 WR_DATA      => s_wr_data2,
	 RD_DATA      => s_rd_data2, 
	 
	 TRIG         => s_adc2_trig,
	 
	 CHAN         => s_adc_chan,
	
	 ADC_VAL     => s_adc2_val
);

U_ADC_3 : ADC 
port map
(
    ADC_CLK  => TOP_CLK,
	 ADC_RST  => TOP_RST,
	 
	 CS           => s_adc3_cs,
	 WR_DONE_CLR  => s_wr_done_clr3,
	 WR_START     => s_wr_start_trig3, 
	 WR_DONE      => s_wr_done3,
	 
	 WR_DATA      => s_wr_data3,
	 RD_DATA      => s_rd_data3, 
	 
	 TRIG         => s_adc3_trig,
	 
	 CHAN         => s_adc_chan,
	
	 ADC_VAL     => s_adc3_val
);

U_ADC_4 : ADC 
port map
(
    ADC_CLK  => TOP_CLK,
	 ADC_RST  => TOP_RST,
	 
	 CS           => s_adc4_cs,
	 WR_DONE_CLR  => s_wr_done_clr4,
	 WR_START     => s_wr_start_trig4, 
	 WR_DONE      => s_wr_done4,
	 
	 WR_DATA      => s_wr_data4,
	 RD_DATA      => s_rd_data4, 
	 
	 TRIG         => s_adc4_trig,
	 
	 CHAN         => s_adc_chan,
	
	 ADC_VAL     => s_adc4_val
);


process (TOP_CLK)
begin

    if (rising_edge(TOP_CLK)) then
	     
        case s_adc_cs_mask is
		  
            when "1110" =>
		       ADC_SS1 <= s_adc1_cs;
			   s_wr_data <= s_wr_data1;
			   s_rd_data <= s_rd_data1;
			   s_wr_start_trig <= s_wr_start_trig1;
			   s_wr_done <= s_wr_done1;
			   s_wr_done_clr <= s_wr_done_clr1;
					 
			when "1101" =>
				ADC_SS2 <= s_adc2_cs;
				s_wr_data <= s_wr_data2;
				s_rd_data <= s_rd_data2;
				s_wr_start_trig <= s_wr_start_trig2;
				s_wr_done <= s_wr_done2;
				s_wr_done_clr <= s_wr_done_clr2;
				
		     when "1011" =>
				ADC_SS3 <= s_adc3_cs;
				s_wr_data <= s_wr_data3;
				s_rd_data <= s_rd_data3;
				s_wr_start_trig <= s_wr_start_trig3;
				s_wr_done <= s_wr_done3;
				s_wr_done_clr <= s_wr_done_clr3;
					 
			  when "0111" =>
				  ADC_SS4 <= s_adc4_cs;
				  s_wr_data <= s_wr_data4;
				  s_rd_data <= s_rd_data4;
				  s_wr_start_trig <= s_wr_start_trig4;
				  s_wr_done <= s_wr_done4;
				  s_wr_done_clr <= s_wr_done_clr4;
					 
			   when others =>
				   ADC_SS1 <= '1';
					ADC_SS2 <= '1';
					ADC_SS3 <= '1';
					ADC_SS4 <= '1';
				    s_wr_start_trig <= '0';
					 
		  end case;
		  
		   
	 end if;

end process;

end behavior;  
  
  

 

 

Так нормально?

Edited by jenya7

Share this post


Link to post
Share on other sites

Bad0512

Я возможно странный вопрос задам, однако : Чем обусловлено наличие двух независимых мастеров в ПЛИС, которые даже не знают о существовании друг друга, то есть не могут договориться об очередности доступа к слейву программно?

Может тут надо на системном уровне в начале проблемы порешать?

 

З Ы Вы конечно можете реализовать честный арбитр, который реализует данную схему доступа, но при этом вам придется добавить интерфейс между мастерами и арбитром (добавить сигналы REQ и GNT в каждый инстанс мастера и "научить" мастера начинать транзакцию только после получения ответа от арбитра. Не такая уж сложная штука вроде бы, но об этом надо помнить.

 

Share this post


Link to post
Share on other sites

jenya7
4 hours ago, Bad0512 said:

Я возможно странный вопрос задам, однако : Чем обусловлено наличие двух независимых мастеров в ПЛИС, которые даже не знают о существовании друг друга, то есть не могут договориться об очередности доступа к слейву программно?

Может тут надо на системном уровне в начале проблемы порешать?

 

З Ы Вы конечно можете реализовать честный арбитр, который реализует данную схему доступа, но при этом вам придется добавить интерфейс между мастерами и арбитром (добавить сигналы REQ и GNT в каждый инстанс мастера и "научить" мастера начинать транзакцию только после получения ответа от арбитра. Не такая уж сложная штука вроде бы, но об этом надо помнить.

 

 действительно. что то я погнал не в ту степь.  опустил CS слейва и общайся с ним. весь арбитраж - общий enable который активный при условии что только один CS опущен.

Edited by jenya7

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.