Jump to content
    

Первый проект на Verilog. Прошу помощи

always @(negedge SS) begin
 txbuf <= spitx;
end

always @(posedge SS) begin
 spirx <= spireg;
end

always @(negedge SCLK or posedge SS) begin
 if (SS) begin
  txld <= 1'b0;
 end else begin
  txld <= 1'b1;
 end
end

assign miso_mux = (~txld) ? txbuf[7] : spireg[7];
assign MISO = (~SS) ? miso_mux : 1'bz;

always @(negedge SCLK) begin
 if (txld) begin
  spireg <= {spireg[6:0], MOSI};
 end else begin
  spireg <= {txbuf[6:0], MOSI};
 end
end

 

Share this post


Link to post
Share on other sites

На этом форуме приводил задачку синтезируемого описания многопортового триггера (те с несколькими клоками), но ветку не нашел (емнип было в ~2010г).

post.png

Edited by Leka

Share this post


Link to post
Share on other sites

module spi_slave(
			input i_core_clk,	//FPGA clock
			
			input wire i_cs,
			input wire i_clk,
			input wire i_mosi,
			output reg o_miso,
				
			output reg o_irq,
			output reg [7:0]o_rx_buf,
			input wire [7:0]i_tx_buf	
);

//----------------------- MOSI -----------------------------
	
	reg [2:0]counter_rx;
	reg [7:0]sr_rx;
	
	//Детектор flag_rx
	reg flag_rx, flag_rx_1, flag_rx_2;
	wire flag_rx_pos;
	assign flag_rx_pos = flag_rx_1 & ~flag_rx_2;
		
	always @(negedge i_core_clk)
	begin
		flag_rx_1 <= flag_rx;
		flag_rx_2 <= flag_rx_1;	
	end	
		
	always @(posedge i_clk or posedge i_cs)
	begin
		if(i_cs) counter_rx <= 3'd0;
		else
		begin
			counter_rx <= counter_rx + 1'd1;
			
			if(counter_rx == 3'd7) flag_rx <= 1'd1;
			else flag_rx <= 1'd0;
		
			sr_rx <= {sr_rx[6:0], i_mosi};
		end
	end
	
	always @(posedge i_core_clk)
	begin
		if(flag_rx_pos)
		begin
			o_irq <= 1'd1;
			o_rx_buf <= sr_rx;
		end
		
		if(o_irq) o_irq <= 1'd0; 
	end
	
//-------------------------- MISO ---------------------------------	
	reg [2:0]counter_tx;
	reg [7:0]sr_tx;

	reg miso_mux, f;
	
	always @(*)
	begin
		if(i_cs) o_miso = 1'bZ;
		else o_miso = miso_mux;
		
		if(f) miso_mux = sr_tx[7]; 
		else miso_mux = i_tx_buf[7];  
	end
	
	always @(negedge i_clk or posedge i_cs)
	begin
		if(i_cs) 
		begin
			f <= 1'd0;
			counter_tx <= 1'd0;
		end	
		else 
		begin
			f <= 1'd1;
			counter_tx <= counter_tx + 1'd1;
			if(!counter_tx && !f) sr_tx <= i_tx_buf << 1'd1; 
			else if(counter_tx == 3'd7) sr_tx <= i_tx_buf;	
			else sr_tx <= sr_tx << 1'd1; 	
		end	
	end
	
endmodule

Что здесь не так? В симуляторе опять всё ОК!

Share this post


Link to post
Share on other sites

Асинхронный сброс придумали мазохисты. В разные точки ПЛИС клок и асинхронный сброс могут приходить в разными относительными задержками, это означает, что могут одновременно выполняться ветви "if" и "else".

Одновременное выполнение ветвей "if" и "else" - возможный побочный эффект асинхронного дизайна, это надо учитывать.

Share this post


Link to post
Share on other sites

Черновик, проверять лень.

module spi_slave(    
    input i_cs,
    input i_clk,
    input i_mosi,
    output o_miso,
    output reg [7:0] o_rx,
    input [7:0] i_tx    
);
reg p_cs, n_cs;
reg [7:0] sr_rx, sr_tx;
assign o_miso = i_cs ? 1'bz : n_cs ? i_tx[7] : sr_tx[7];  
always @(posedge i_cs) begin 
    o_rx <= sr_rx;
end    
always @(posedge i_clk) begin 
    p_cs <= i_cs;
    if(! i_cs) 
        sr_rx <= {sr_rx, i_mosi};
end
always @(negedge i_clk) begin
    n_cs <= p_cs;    
    if(! p_cs) 
        if(n_cs) 
            sr_tx <= {i_tx, 1'b0};
        else 
            sr_tx <= {sr_tx, 1'b0};
end    
endmodule
Edited by Leka

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

 Это м/б "SPI bus-compatible serial interface" (фраза из даташита на загрузочную флешку).

Просто хотел привести вариант кода без асинхронных гонок для конкретной задачи.

Для этого cs пропустил последовательно через "posedge i_clk" и "negedge i_clk".

Share this post


Link to post
Share on other sites

Добавил к предыдущему своему коду полутактовые буферы на MOSI и параллельную загрузку, теперь это железобетонный асинхронный SPI slave:

 

always @(negedge SS) begin
 txbuf <= spitx;
end

always @(posedge SS) begin
 spirx <= spireg;
end

always @(negedge SCLK or posedge SS) begin
 if (SS) begin
  txsw <= 1'b0;
 end else begin
  txsw <= 1'b1;
 end
end

always @(posedge SCLK) begin
 txld <= txsw;
 mosibuf <= MOSI;
end

assign miso_mux = (~txsw) ? txbuf[7] : spireg[7];
assign MISO = (~SS) ? miso_mux : 1'bz;

always @(negedge SCLK) begin
 if (txld) begin
  spireg <= {spireg[6:0], mosibuf};
 end else begin
  spireg <= {txbuf[6:0], mosibuf};
 end
end

Share this post


Link to post
Share on other sites

Цитата

Для этого cs пропустил последовательно через "posedge i_clk" и "negedge i_clk"

Логика работы мне немного не подходит. Ваш вариант требует обязательного наличия сигналов i_clk во время высокого уровня i_cs. Загрузка в выходной буфер o_rx из sr_rx только при фронте i_cs, а не после принятия последнего бита.   

Edited by pinchemierda

Share this post


Link to post
Share on other sites

Согласен, логика может не подходить. Но гарантировать отсутствие клока при высоком уровне cs можно только в случае одного устройства spi slave на шине. Надо разбираться, но сам всегда избегаю использования асинхронного сброса.

Если устройство одно, и клок есть только при низком уровне cs, это сильно упрощает задачу, и д/б отражено в ТЗ.

Share this post


Link to post
Share on other sites

Цитата

теперь это железобетонный асинхронный SPI slave

Протокол SPI slave подразумевает загрузку принятых данных только по фронту CS? И должно ли быть так, что всё что приходит от мастера возвращается по MISO следующим байтом (эхо)?

Share this post


Link to post
Share on other sites

Счетчик бит лучше не использовать, если гарантировать нужное число тактов клока при низком cs.

Share this post


Link to post
Share on other sites

Просто если к примеру подчинённый один, то мастер будет всегда держать линию CS в нуле. Сигналов на линии CS вообще не будет почти никогда. Для любого устройства с SPI slave это не должно быть проблемой. 

Share this post


Link to post
Share on other sites

2 минуты назад, pinchemierda сказал:

Протокол SPI slave подразумевает загрузку принятых данных только по фронту CS?

По стандарту, во время сеанса, принадлежность данных, проходящих транзитом сквозь соединённые в цепочку устройства, естественно не определена, лишь по его завершении.

 

7 минут назад, pinchemierda сказал:

должно ли быть так, что всё что приходит от мастера возвращается по MISO следующим байтом (эхо)?

По стандарту, мастер в сеансе выдаёт ровно столько тактов, сколько бит в сумме у всех сдвиговых регистров, соединённых в цепочку — соответственно, все одновременно загруженные в начале сеанса по единому SS и выдвинутые из устройств биты достаются мастеру, а выдвинутые из него — устройствам, которые получают их тоже одновременно по снятию единого SS. Таким образом, счётчик битов есть лишь у мастера, чтобы во время сеанса передавать и принимать байтами, словами и т.д., как ему удобнее. Устроить "эхо", выдавая больше тактов, чем количество бит в системе, т.е. тупо гонять данные по кругу, конечно можно, но бессмысленно.

Share this post


Link to post
Share on other sites

А нужна цепочка ТС? Если конечная задача - сделать spi мост между МК и конкретной схемой, не стоит усложнять.

 

|| соединение spi устройств с индивидуальными cs вроде чаще встречается.

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.

×
×
  • Create New...