Jump to content

    
pinchemierda

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

Recommended Posts

3 minutes ago, pinchemierda said:

К мастеру вопросов точно нет. В синхронном варианте связка МК <-> ПЛИС работает, только частота не максимальная, а 9МГц.

Этот рабочий код можете выложить? ("В синхронном варианте ... только частота не максимальная, а 9МГц.")
Вместе с тестбенчем, естественно

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	
);

	reg [2:0]counter;							//счётчик битов
	
	//детектор CLK
	reg clk_1, clk_2; 
	wire clk_pos, clk_neg;
	assign clk_pos = clk_1 & ~clk_2;
	assign clk_neg = ~clk_1 & clk_2;
	
	//детектор CS
	reg cs_1, cs_2; 
	wire cs_neg;
	assign cs_neg = ~cs_1 & cs_2;
	
	always @(posedge i_core_clk)
	begin
		clk_1 <= i_clk;
		clk_2 <= clk_1;
		
		cs_1 <= i_cs;
		cs_2 <= cs_1;
		
		if(clk_pos && !cs_2) counter <= counter + 1'd1;
		if(cs_neg) counter <= 3'd0;
	end
	
//----------------------- MOSI -----------------------------
	reg [7:0]sr_rx;							//сдвиговый приёмный регистр 
	reg rx_flag;
	
	always @(posedge i_core_clk)
	begin
		if(clk_pos && !cs_2)
		begin
			sr_rx <= {sr_rx[6:0], i_mosi};
			if(counter == 3'd7) rx_flag <= 1'd1;
		end
		
		if(rx_flag) 
		begin
			rx_flag <= 1'd0;
			o_irq <= 1'd1;
			o_rx_buf <= sr_rx;
		end
		
		if(o_irq) o_irq <= 1'd0;  
	end

//-------------------------- MISO ---------------------------------	
	reg [7:0]sr_tx;							//сдвиговый регистр отправки

	always @(*)
	begin
		if(cs_2) o_miso = 1'dZ;
		else o_miso = sr_tx[7];  
	end

	always @(negedge i_core_clk)
	begin
		if(o_irq || cs_neg)
		begin
			sr_tx <= i_tx_buf;
		end
	
		if(clk_neg && !cs_2 && counter)
		begin
			sr_tx <= sr_tx << 1'd1;
		end
	end
	
endmodule

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

Только что, nice_vladi сказал:

Сдаётся мне, это тоже будет работать только при соотношении клоков iclk/isclk = 10/1 (минимум). 

Edited by pinchemierda

Share this post


Link to post
Share on other sites
19 minutes ago, pinchemierda said:

Сдаётся мне, это тоже будет работать только при соотношении клоков iclk/isclk = 10/1 (минимум). 

Так можно отсимулить. Там есть ТБ

Share this post


Link to post
Share on other sites
1 hour ago, pinchemierda said:

К мастеру вопросов точно нет. В синхронном варианте связка МК <-> ПЛИС работает, только частота не максимальная, а 9МГц.

Использование o_irq может скрывать логические ошибки.

 

В синхронном варианте клоком является хороший сигнал от генератора 50МГц на той-же плате.

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

Edited by Leka

Share this post


Link to post
Share on other sites
Только что, Leka сказал:

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

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

Share this post


Link to post
Share on other sites
9 minutes ago, pinchemierda said:

Является ли это подтверждением того, что spi клок подходящего качества?   

Да, наверно. 

 

10 minutes ago, pinchemierda said:

убрать из кода всё связанное с отправкой по MISO

Непонятно, как это может повлиять на прием. 

12 minutes ago, pinchemierda said:

Если убрать из кода всё связанное с отправкой по MISO (оставить только приём по MOSI) приём начинает работать правильно и очень стабильно (и на любой скорости).

К моему коду это тоже относится?

(кстати, немного поправил свой код)

Share this post


Link to post
Share on other sites
Только что, Leka сказал:

К моему коду это тоже относится?

Это вообще к любому варианту относится. И к синхронному и к асинхронному (в том числе вашему). Даже к самому начальному, на который все очень сильно ругались. Я это с самого начала отметил. 

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

Не знаю, стоит ли на этом заострять внимание, потому что решением проблемы в синхронном варианте было применение детекторов фронтов по spi_clk и spi_cs. И для меня совсем не понятно, почему без них приём работал отлично (если только приём!), а с отправкой не работало.

Хотя, как уже писали, когда в синхронном дизайне вылезают проблемы связанные с асинхронщиной, возникает метастабильность и всё такое... И там уже логического объяснения происходящего быть не может (бесовщина полная может твориться).

Share this post


Link to post
Share on other sites
17 minutes ago, pinchemierda said:

Не знаю, стоит ли на этом заострять внимание

Стоит, spi-slave должен работать от клока мастера, без каких-либо дополнительных клоков. Зачем лишние сущности? 

Еще момент, если используется z-состояние выхода, пин надо объявить так:

inout MISO

Но если других устройств нет, лучше не делать с z-состоянием.

Share this post


Link to post
Share on other sites
1 час назад, nice_vladi сказал:

Это ещё и систем верилог, что ли? Не могу перевести эту строку в верилог:

omiso <= tx_shift_reg[$high(tx_shift_reg)]; 

Share this post


Link to post
Share on other sites
4 часа назад, pinchemierda сказал:

изредка нормализуется приём на пару секунд (особенно если свободные контакты руками полапать)

Покажите нам фото этой экспериментальной установки, потому что в общем случае передача таких частот даже на 10 мм требует соответствующий конструктив, включая монтаж и линии связи.

Share this post


Link to post
Share on other sites
4 hours ago, pinchemierda said:

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

 


Ладно, в целом нормально. Хотя reset-а все равно нет, но я уже понял, что вас не додавить.
Кстати, вы уже наверное почувствовали разницу между "стабильно работает" и "работает, если полапать незанятые пины".
Вот то-то и оно.
 

Теперь по стилю.. Знаете, - можно писать стихи без глаголов, а у вас в коде совсем нет ELSE-ов. 
Может они и правда здесь не нужны, но мне кажется причина в чем-то другом. 
Взять например этот фрагмент:

always @(posedge i_core_clk)
    begin
        
        if(clk_pos && !cs_2) counter <= counter + 1'd1;
        if(cs_neg) counter <= 3'd0;
    end
 

Очевидно же, что приоритет обнуления счетчика должен быть выше, - то есть код должен выглядеть вот так:

always @(posedge i_core_clk)
    begin
        if(cs_neg)
           counter[2:0] <= 3'd0;
                else
        if (clk_pos && !cs_2)
           counter[2:0] <= counter[2:0] + 3'd1;
        
    end

Это как минимум улучшает понимание, даже если эти события во времени и не пересекаются никогда.
 

Далее, снова эта ваша привычка, зачем засунули sr_rx и rx_flag под один always ??
 

    always @(posedge i_core_clk)
    begin
        if(clk_pos && !cs_2)
            sr_rx[7:0] <= {sr_rx[6:0], i_mosi};
         end
 

Всё! Дальше пошел другой always.

    always @(posedge i_core_clk)
    begin
          здесь только формирование rx_flag !!!
        end

и так далее
 

Теперь по вашей проблеме. Сейчас нет времени разбираться хватит ли 50MHz чтобы принимать на частоте SPI 18MHz. Но я так понял, вы в это уперлись. 
Была бы PLL - поставили бы PLL. Но её нет. Сделать-то на самом деле можно - собирайте 4 бита в одном регистре (по нечетным значениям счетчика counter) и 4 бита в другом регистре по четным значениям счетчика counter. Соответствующие стробики будут наезжать на следующий такт SCLK, но это не страшно - в параллель будут работать два "плеча".  Но если так делать не хотите, предлагаю довольно некрасивый hack. Сделать удвоитель частоты на логике. Тогда получите 100 MHz тактовую частоту (не меандр, короткие импульсы). Как сделать - по ссылке (см. Удвоитель частоты). Автор удвоителя - Peter Alfke

https://tqfp.org/fpga/shest-prostyh-asinhronnyh-histrostey.html

Share this post


Link to post
Share on other sites
1 hour ago, pinchemierda said:

Не работает на любой частоте, даже на 1 МГц.

Надписи хорошо-бы сделать, где какие провода. Очень м/б, что проблема именно тут.

15 minutes ago, Джеймс said:

Это как минимум улучшает понимание, даже если эти события во времени и не пересекаются никогда.

Варианты кода равнозначны, независимо от "пересечения событий во времени".

Edited by Leka

Share this post


Link to post
Share on other sites
58 минут назад, pinchemierda сказал:

Не работает на любой частоте

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

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.