Jump to content

    
pinchemierda

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

Recommended Posts

On 6/24/2020 at 12:40 AM, pinchemierda said:

ТЗ: 

1. После принятия посылки из 8 бит по линии i_mosi, модуль должен сформировать сигнал o_irq длительностью 1 такт и выдать принятые данные на внешний порт o_rx_buf.

2. Спустя минимальное количество времени после спада i_cs или фронта o_irq должны защёлкиваться 8 бит на параллельном входе i_tx_buf. Затем этот байт должен быть передан последовательно (в соответствии с протоколом SPI CPHA=0, CPOL=0) по линии o_miso.  

Ну сейчас то уж синхронней некуда)):

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

отлично, теперь вы знаете к чему стремиться и у вас есть основа для быстрой проверки изменений (кстати фазы вашего выхода, не соответствуют протоколу SPI 00 https://ru.wikipedia.org/wiki/Serial_Peripheral_Interface, но это не должно особо мешать).

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

Но вот какой факт, вы оставили без внимания: квартус переделал ваш логику, т.к. вы не корректно ее описали. Отметил эти моменты на скриншоте. Раньше квартус выдавал предупреждение об этом, но новые похоже делают так, как считают нужными. В итоге, помимо прочего, ваш асинхронный сигнал тянется через всю логику и логика отличается от того, что вы задумали. И да, симулятор эти моменты вам не покажет. Нужно работать дальше) 

spi.png

Share this post


Link to post
Share on other sites

Я бы все же рекомендовал вам начать с ТЗ попроще. Но довести его до конца.

ТЗ #0:

0. Общая постановка задачи

Реализовать счетчик-делитель с изменяемым коэффициентом деления. Главный выход счетчика должен иметь duty cycle 50%. Служебный выход heartbeat должен выдавать сигнал с частотой 1 Гц, duty cycle 50% независимо от программируемого коэффициента деления.

1. В качестве тактового сигнала должен использоваться тактовый сигнал на PIN_64 (50 MHz).

2. У устройства д.б. следующие режимы работы:

  • IDLE - режим ожидания, он же режим по умолчанию после выхода из состояния RESET;
  • SETUP - режим задания коэффициента деления
  • COUNT - режим счета с заданным коэффициентом

3. У счетчика д.б. следующие органы управления:

  • 1 кнопка RESET (manual) - помимо внутреннего сигнала pwron_rst_n, получаемого в конечном счете с PIN_44
  • 1 кнопка MODE переключения режима работы; переключение - циклическое: IDLE => SETUP => COUNT => IDLE ...
  • 1..n кнопок или переключателей для задания коэффициента деления в режиме SETUP (зависит от выбранного способа ввода)

4. У счетчика д.б. следующие средства индикации (с возможностью вывода на LEDs):

  • 2-bit выход STATE - для индикации режима работы или состояния управляющей машины состояний (включая ее состояние RESET)
  • 1-bit выход HEARTBEAT - для индикации признаков жизни/счета/работоспосбности-наличия входного клока и т.п.
  • N-bit выход DIVIDE_COEFF - для индикации действующего коэффициента деления

5. Основные продукты работы устройства:

  • главный выход счетчика CLK_OUT должен быть выведен на PIN_xx
  • служебный выход HEARTBEAT д.б. выведен на PIN_yy.
  • опционально м.б. выведены для контроля промежуточные сигналы делителя на PIN_aa .. PIN_bb.

6. Входы устройства:

  • PWRON_RST_N (Power-On Reset) : PIN_44
  • RESET_N (manual reset from button) : PIN_rr
  • MODE (выбор режима) : PIN_zz

......

7. Выходы устройства (кроме указанных в п.5):

......

Примерно вот так. При реализации такого ТЗ вам придется соприкоснуться с многими моментами разработки реальных устройств. И в то же время устройство имеет обозримую сложность.

Share this post


Link to post
Share on other sites
25.06.2020 в 00:46, Raven сказал:

а натягивание на 18 МГц при клоке 50 - тут без асинхронщины не обойтись

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

Только всё равно не понимаю, почему так не работает:

always @(posedge i_core_clk)
begin
  sync_clk <= i_clk;
  sync_cs <= i_cs;
end

а так работает:

	//детектор фронта CLK
	reg clk_1, clk_2; 
	wire sync_clk;
	assign sync_clk = clk_1 & ~clk_2;
	
	//детектор спада CS
	reg cs_1, cs_2; 
	wire sync_cs;
	assign sync_cs = ~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;
	end

Последний вариант игнорировал, потому что он медленнее. Уж не знаю насколько сейчас правильно с фундаментальной (академической) точки зрения, но работает без каких либо reset-ов (я не говорю, что он не нужен, но конкретно в этом проекте, вероятно, можно обойтись и без него). С такими детекторами фронтов CLK и CS всё правильно отправляется и принимается, только на скорости не выше 8МГц. В общем, вариант не быстрее, чем реализация через автомат состояний, как в том посту. И не могу сказать, что результат меня устраивает. Как можно без асинхронщины натянуть на 18МГц при клоке в 50МГц?

Цитата

а соответствующие констрейны написаны?

Полез искать, что это вообще такое. Если правильно понял, это необходимо при асинхронном дизайне. Мне бы пока с синхронным разобраться.

Share this post


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

Только всё равно не понимаю, почему так не работает:

...

а так работает:

...

Уже сказано, почему - см. про метастабильность.

Ваш 2-й вариант все еще недостаточно свободен от эффектов метастабильности, т.к. составляющие clk_1 и cs_1 прошли только один триггер в синхронизирующей цепочке, а не 2, как положено.

Quote

Как можно без асинхронщины натянуть на 18МГц при клоке в 50МГц?

Чтобы нормально и стабильно работало - боюсь, что никак. О чем сразу и сказал. Соотношение периодов - 56 нс и 20 нс - практически не оставляет пространства для маневра в синхронной схеме.

Quote

Полез искать, что это вообще такое. Если правильно понял, это необходимо при асинхронном дизайне. Мне бы пока с синхронным разобраться.

Нет, неправильно вы поняли. Если говорить о временнЫх констрейнтах (а констрейнты, они же ограничения, есть еще и физические - назначение пинов, привязка кусков логики к определенным внутренним блокам и т.п.), то в первую очередь они нужны для синхронных дизайнов, чтобы как раз описать рамки, в которые синтезатор должен загонять синтезируемую схему, чтобы она была синхронной и в ней все было хорошо. Да вообще весь инструментарий разработчика FPGA, который на слуху и с которым вам предстоит работать, предназначен, в основном, для синхронных дизайнов.

 

Вступая на поле асинхронщины, разработчик, в основном, остается без поддержки со стороны констрейнтов и инструментов статического временного анализа (которые как раз эти временнЫе констрейнты и используют в качестве целевых ориентиров), и должен действовать во многом на свой страх и риск. Хорошо еще, что симулятор остается верным товарищем. Но его помощь - только на его собственном поле. Можно попробовать применить аппарат временных констрейнтов для асинхронного дизайна, но результат такого применения интрумента в области, для которой он не предназначен, в общем-то, будет далек от удобства (как минимум). Чтобы описать ограничения для синтезатора, придется ему в констрейнтах расписывать требуемые времена распространения и задержки для массы сигналов (что в варианте для синхронного дизайна выражается всего 5-10 строками, здесь придется подробно расписывать в ... даже не знаю скольких строках, потому как зависит от устройства и его сложности). Для маленьких конструкций это, наверное, при определенной упертости, еще подъемно, но для серьезного устройства - увы...

Share this post


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

Как можно без асинхронщины натянуть на 18МГц при клоке в 50МГц?

Не надо ничего "натягивать", spi slave должен работать от входного клока 18МГц, а 50МГц не использовать, если в дизайне нет других блоков. Если есть, разобраться с переводами между клоковыми доменами, но это потом, когда заработает spi от клока 18МГц.

Share this post


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

spi slave должен работать от входного клока 18МГц, а 50МГц не использовать

У автора не SPI, а просто последовательный интерфейс — SPI не берёт чужие данные на лету и у него нет никаких счётчиков бит. К тому же, этот интерфейс должен быть синхронным, потому что ТЗ требует после сеанса создать некий сигнал прерывания длиной в 1 такт — стандартный SPI на такое не способен, он не выдаёт лишних тактов после сеанса.

Share this post


Link to post
Share on other sites

Но если немного видоизменить ТЗ, и этот тактовый сигнал достаточно стабилен - то это вполне вариант для ТС. Но на его месте я все же воспользовался бы возможностью поучиться чему-то за рамками этой узкой, весьма конкретной задачи (SPI).

Share this post


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

В идеале SPI 0 slave хотелось бы получить.

Тогда все делать в домене i_clk, прием по always@(posedge i_clk), сдвиг регистра передачи по always@(negedge i_clk).

 

 

Edited by Leka
было неверно

Share this post


Link to post
Share on other sites

Да вот и не получается придумать, как передачу по o_miso сделать в блоке always@(posedge i_clk). Надо как то данные из i_tx_buf защёлкивать в сдвиговый регистр при спаде i_cs и после восьми клоков. С приёмом по линии i_mosi понятнее.

Share this post


Link to post
Share on other sites

У меня ошибка была, передача д/б по always@(negedge i_clk). 

i_cs можно использовать только для перевода выхода из Z-состояния в активное, и разрешения клока i_clk.

Защелкивать данные в выходной регистр надо только по клоку i_clk.

Edited by Leka

Share this post


Link to post
Share on other sites
Цитата

передача д/б по always@(negedge i_clk). 

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

Цитата

Защелкивать данные в выходной регистр надо только по клоку i_clk.

А как передавать самый первый бит? Он же сразу должен появиться после спада i_cs. А когда приходит самый первый фронт i_clk он уже должен быть выставлен на выходе o_miso.

Прошу прощения, вы про выходной регистр. С ним то понятно всё и проблем нет.

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

Share this post


Link to post
Share on other sites

Во входной сдвиговый защелкивать по posedge, в выходной по negedge.

o_miso д/б подключен к 7 биту не входного, а выходного регистра. 

Данные для выходного регистра можно брать с входного регистра.

Share this post


Link to post
Share on other sites

Выходной регистр у меня это o_rx_buf. В нём появляется то, что пришло по линии i_mosi. Зачем к нему подключать выход o_miso?

i_tx_buf - это входной буфер того что необходимо отправить по линии o_miso. В общем, как этот буфер не называй, всё равно не понятно, как обновлять в нём байт на отправку при спаде i_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.