Продолжаю потихоньку осваивать ПЛИС. На сей раз раскурим подключение и объединение модулей.
После тестирования SPI, попытался совместить Atmega8 и EPM240, в надежде сделать генератор: avr задает — плис молотит, что получилось расскажу в ближайшее время. Стало понятно что 240 ячеек это совсем грустно, но даже овладев методом фоторезиста, сделать подобную плату без единого косяка и с первого раза, достаточно трудоемко. В планах было распаять EP3C5E144C8N и на ее основе пилить обзоры дальше. Камень закуплен, но на текущий момент, я отказался от этой затеи, возможно позже вернусь.
Нужно было найти какую то альтернативную готовую железяку, поэтому были прочесаны все возможные варианты, в качестве аргументов были — минимальная обвязка, наличие достаточного количества выходов-штырьков, наличие памяти и много, очень много логических элементов. Итого или Ebay, или Ebay, ничего приличного купить в здешних краях за разумную цену невозможно. В общем зная себя, я все таки решил купить у местных барыг, это личное решение, не следуйте ему. Собственно единственное, что было это DE0 nano. Платка мелкая, на борту Циклон4 с 22к ЛЭ, остальное лирика.
Это вместо вступления. Теперь перейдем к самому интересному. Ранее мы пробовали делать какие то свои элементы UART, SPI, но на самом деле их не обязательно делать самостоятельно. Какие же варианты существуют? Некоторые вещи можно качать в интернете, желательно с сайта альтеры, примеров там много и они более менее годные. Есть проект OpenCores. Но кое что попроще есть и в комплекте квартуса. К сожалению это не Verilog модули, но об этом далее.
Если вам известно, то в квартусе можно пилить прошивку не только путем описания на Verilog или VHDL. Делается это так, создается новый файл схематика
Далее жмакаем правой кнопкой мыши
Появится окошко библиотеки, в котором нас ожидает куча всяких элементов, начиная от простых, заканчивая сложными.
Например, можно вытащить сдвиговый регистр
Собственно можно навытаскивать кучу компонентов, соединить их как надо и все будет работать. Но не всегда это удобно. Если проект не большой, то работать со схемой может показаться удобным. Но вот пример обыкновенной мигалки из первого проекта. На мой взгляд 2 строчки кода понятнее, чем такая схема.
В итоге, у нас есть библиотеки, но они написаны не на верилоге. Выходов из этой ситуации несколько. Можно сделать так: ищем нужный нам элемент из схематика, далее жмакаем File — Create/Update — Create HDL Design From current file. Таким образом мы можем конвертнуть элемент в Verilog. Не очень удобно, кроме того зачастую криво конвертится, поэтому нужно тщательно проверять результат. Но главное возможность такая имеется.
Другой вариант — написать свой модуль на верилоге, а окончательно все модули в том числе и библиотечные, соединить в схематике. Это намного более удобно и быстро, но не забываем, что переносимости между разными семействами не будет.
Перед тем как рассказать про еще один способ, неплохо будет рассказать о том, как соединяются все это в «чистом» Verilog. Допустим вы реализовали некий led, с некой логикой, важно то что есть вход clk и выход pin, остальное не важно
module led(clk,pin); input clk; output reg pin; always begin pin <= clk; end endmodule |
Также имеется главный модуль, в котором вы хотите объединить/соединить остальные.
module m_test(clock); input clock; endmodule |
Допустим наша цель подключить ко входу clock вход clk. Делается это так:
module m_test(clock); input clock; led ld(.clk(clock)); endmodule |
led — это имя исходного модуля, ld — это произвольное имя элемента, ибо если нужно будет подключить одинаковых модулей, их нужно как то различать, clk это нога led, clock это нога m_test т.е. куда соединяем.
Чтобы было совсем понятно, добавим еще один
module m_test(clock); input clock; led ld(.clk(clock)); led ldd(.clk(clock)); endmodule |
Таким образом можно все упаковывать в одну кучу. Но вернемся к нашей проблеме. Есть еще один способ, если хочется юзать Verilog и либу схематика, находите имя символа схематика, запоминаете его ноги и тупо делаете так:
module m_test(clock, port); input clock; output port; dff hc(.d(clock), .q(port)); endmodule |
т.е. совершенно не парясь в верилоговский файл запихиваете символ из схематика, причем больше никаких телодвижений не нужно, все компилится как надо, dff это библиотечный триггер.
Ну и пример совмещения. Используем нашу FPGA просто как обычную логику, допустим нам нужно подключить светодиоды через сдвиговый регистр. Для управления микроконтроллер Atmega8. Вставляем регистр без защелки 74164(можно конечно и 595). Увы цифры в именах использовать нельзя, поэтому сохраним его в папке проекта под именем hc74164.
И на схемке подправим имя. Заодно можно выкинуть разрешающий вход B он не шибко нужен.
Главный модуль напишем на Verilog, управлять будем по SPI, поэтому входные сигналы: data это MOSI, clock — CLK. ss — сброс регистра. Принимаем число по SPI от микроконтроллера, загоняем его в сдвиговый регистр. Выход регистра это восьмибитный порт со светодиодами.
module m_test(clock, led_port, data, ss); input clock; input data; input ss; output [7:0]led_port; hc74164 hc(.CLK(clock), .A(data), .QA(led_port[0]), .QB(led_port[1]), .QC(led_port[2]), .QD(led_port[3]), .QE(led_port[4]), .QF(led_port[5]), .QG(led_port[6]), .QH(led_port[7]), .CLRN(ss)); endmodule |
Со стороны микроконтроллера — посылаем число по SPI, ждем 0.5с увеличиваем число и так до 254, после начинаем заново с нуля. Перед каждой отправкой сбрасываем регистр.
#include <mega8.h> #include <delay.h> #include <spi.h> void main(void) { // Declare your local variables here char x=0; // Input/Output Ports initialization // Port B initialization // Function: Bit7=In Bit6=In Bit5=Out Bit4=In Bit3=Out Bit2=Out Bit1=In Bit0=In DDRB=(0<<DDB7) | (0<<DDB6) | (1<<DDB5) | (0<<DDB4) | (1<<DDB3) | (1<<DDB2) | (0<<DDB1) | (0<<DDB0); // State: Bit7=T Bit6=T Bit5=0 Bit4=T Bit3=0 Bit2=0 Bit1=T Bit0=T PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // SPI initialization // SPI Type: Master // SPI Clock Rate: 2000,000 kHz // SPI Clock Phase: Cycle Start // SPI Clock Polarity: Low // SPI Data Order: MSB First SPCR=(0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0); SPSR=(0<<SPI2X); while (1) { if(x <254) x++; else x = 0; spi(x); delay_ms(500); PORTB.2=0; #asm("nop"); PORTB.2=1; } } |
Пример очень простой, так и задумано. Можно было бы извернуться одним схематиком, но представим, что главный модуль включает в себя еще много мелких частей, кроме этой.
Результат:
Если подвести итог, лучше конечно все модули писать на Verilog, ибо сегодня Altera, завтра Xilinx или еще что то. Но если нужно побыстрому что то проверить, то можно скрестить бульдога с носорогом.
Спасибо огромное! Помогло 😀