jenya7 0 Posted January 24 · Report post Есть два мастер SPI которые пользуются общими пинами в TOP ENTITY Я могу сделать так 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 или есть более правильное решение? Quote Ответить с цитированием Share this post Link to post Share on other sites
Flip-fl0p 0 Posted January 24 · Report post Только что, jenya7 сказал: Есть два мастер SPI которые пользуются общими пинами в TOP ENTITY Я могу сделать так 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 или есть более правильное решение? Арбитр доступа которой рулит коллизиями, когда оба мастера хотят поиметь слейва. Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 (edited) · Report post 9 minutes ago, Flip-fl0p said: Арбитр доступа которой рулит коллизиями, когда оба мастера хотят поиметь слейва. а как его сделать правильно? я еще не знаю но либо контроллер обратиться с командой с номером канала, либо я периодически опрошу. как бы всё детерминировано... Edited January 24 by jenya7 Quote Ответить с цитированием Share this post Link to post Share on other sites
des00 0 Posted January 24 · Report post 35 minutes ago, jenya7 said: Но вот гложет меня сомнение правильно комутирировать с OR или есть более правильное решение? AND-OR мультиплексор вещь обычная и довольно часто используемая, но, т.к. тут есть два канала управления (которые маски), требуется обеспечить режим, чтобы оба мастера не могли быть активными. Если вы делаете это на административном уровне и у вас всегда, у выключенного мастера сигналы падают в 0, то вы все сделали верно. Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 (edited) · Report post 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 January 24 by jenya7 Quote Ответить с цитированием Share this post Link to post Share on other sites
des00 0 Posted January 24 · Report post 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 Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 · Report post 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); Quote Ответить с цитированием Share this post Link to post Share on other sites
des00 0 Posted January 24 · Report post 2 minutes ago, jenya7 said: тогда наверно так? ADCS_SCLK <= (s_adc1_clk and not adc_ss1) or (not s_adc2_clk and adc_ss2); по управлению вам виднее какой у вас уровень активный) смысл я думаю вы поняли) но вот зачем инвертировать вторую тактовую я не понял) Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 · Report post 1 minute ago, des00 said: вам виднее какой у вас уровень активный) смысл я думаю вы поняли) но это всё равно не блокирует. я же могу оба CS опустить. Quote Ответить с цитированием Share this post Link to post Share on other sites
des00 0 Posted January 24 · Report post 10 minutes ago, jenya7 said: но это всё равно не блокирует. я же могу оба CS опустить. эмм. Вы вообще не читаете мои ответы? Quote требуется обеспечить режим, чтобы оба мастера не могли быть активными. (adc_ss1 =1) & (adc_ss2 = 1) естественно запрещенная ситуация. Если они у вас работают асинхронно, тогда ставьте арбитр включения модулей, любого типа: каруселька, раундробин, приоритетный. UPD. Именно арбитр включения модуля, а не мультиплексирования транзакции SPI. Т.к. SPI транзакцию рвать нельзя. Самое простое сделать сигнал Enable в модулях и уже ими управлять исходя из поступающих запросов на доступ к SPI. А для мультиплексирования, сделать все сигналы в пассивном состоянии 0. на верхнем уровне простой OR. Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 (edited) · Report post спасибо. буду думать над арбитром. раньше было много пинов так все чипы садили на отдельные пины поэтому таких вопросов не возникало. теперь с пинами напряг и все чипы садят на один SPI. Edited January 24 by jenya7 Quote Ответить с цитированием Share this post Link to post Share on other sites
des00 0 Posted January 24 · Report post 5 minutes ago, jenya7 said: раньше было много пинов так все чипы садили на отдельные пины поэтому таких вопросов не возникало. теперь с пинами напряг и все чипы садят на один SPI. я бы сделал один SPI модуль и к нему приделал многоканальный арбитр доступа. Ну а сами источники транзакций пусть работают по простому valid & ready интерфейсу) А если ready не подразумевается в источниках транзакций, сами транзакции редкие, а запрос - импульс длительностью 1 такт, то просто захватываете его, на арбитр, как он получил доступ, сбрасываете его. Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 24 (edited) · Report post 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 January 24 by jenya7 Quote Ответить с цитированием Share this post Link to post Share on other sites
Bad0512 0 Posted January 25 · Report post Я возможно странный вопрос задам, однако : Чем обусловлено наличие двух независимых мастеров в ПЛИС, которые даже не знают о существовании друг друга, то есть не могут договориться об очередности доступа к слейву программно? Может тут надо на системном уровне в начале проблемы порешать? З Ы Вы конечно можете реализовать честный арбитр, который реализует данную схему доступа, но при этом вам придется добавить интерфейс между мастерами и арбитром (добавить сигналы REQ и GNT в каждый инстанс мастера и "научить" мастера начинать транзакцию только после получения ответа от арбитра. Не такая уж сложная штука вроде бы, но об этом надо помнить. Quote Ответить с цитированием Share this post Link to post Share on other sites
jenya7 0 Posted January 25 (edited) · Report post 4 hours ago, Bad0512 said: Я возможно странный вопрос задам, однако : Чем обусловлено наличие двух независимых мастеров в ПЛИС, которые даже не знают о существовании друг друга, то есть не могут договориться об очередности доступа к слейву программно? Может тут надо на системном уровне в начале проблемы порешать? З Ы Вы конечно можете реализовать честный арбитр, который реализует данную схему доступа, но при этом вам придется добавить интерфейс между мастерами и арбитром (добавить сигналы REQ и GNT в каждый инстанс мастера и "научить" мастера начинать транзакцию только после получения ответа от арбитра. Не такая уж сложная штука вроде бы, но об этом надо помнить. действительно. что то я погнал не в ту степь. опустил CS слейва и общайся с ним. весь арбитраж - общий enable который активный при условии что только один CS опущен. Edited January 25 by jenya7 Quote Ответить с цитированием Share this post Link to post Share on other sites