- PVSM.RU - https://www.pvsm.ru -
MIPSfpga микропроцессор MIPS32 microAptiv описаный на языке Verilog для образовательных целей фирмы Imagination, который имеет кэш-память и блок управления памятью. Код процессора доступен пользователю (инструкция по скачиванию [1]) и может использоваться для моделирования и реализации процессора на FPGA плате.
Данная статья является продолжением статьи о том как портировать MIPSfpga-plus на другие платы [2], и в ней будет описано как интегрировать периферию в систему MIPSfpga:
Так же о том как начать работать с MIPSfpga написано в статье:
habrahabr.ru/post/275215 [3]
Процессор использует интерфейс памяти для связи с периферийными устройствами. То есть, это означает что данные записываются и считываются с подключенной периферии так же, как и с блока памяти RAM. Интеграция периферии в процессор осуществляется подключением к шине AHB-Lite(подробная документация [4]). Подробней попробуем разобраться в процессе подключения.
Для начала нужно иметь понятие как будут проходить сигналы по шине AHB-Lite:
Видно, что процесс считывания данных с периферии осуществляется по сигналу HRDATA, передача данных производится по HWRITE с активным высоким уровнем на сигнале разрешения записи, выбор GPIO осуществляется выбором адреса на HADDR.
Первым датчиком который был подключён это 16 кнопочный pmod KYPD (даташит [5])
Распиновка и сигналы клавиатуры описаны в таблице:
Пин | Сигнал | Назначение | Пин | Сигнал | Назначение |
---|---|---|---|---|---|
1 | Col4 | 4 колонка | 7 | ROW4 | 4 ряд |
2 | Col3 | 3 колонка | 8 | ROW3 | 3 ряд |
3 | Col2 | 2 колонка | 9 | ROW2 | 2 ряд |
4 | Col1 | 1 колонка | 10 | ROW1 | 1 ряд |
5 | GND | контакт земли | 11 | GND | контакт земли |
6 | GND | контакт питания | 12 | VCC | контакт питания |
схема подключения клавиатуры очень простая:
Следующим шагом для интеграции клавиатуры к шине AHB-lite будет написание модуля на Verilog. На схеме показано что ряды подтянуты к питанию сопротивлениями в R=10к, это значит что активный сигнал на них будет низким, а на каждую колонку с определенной частотой подается тактовый сигнал (низкий уровень). В момент когда активный сигнал на входе совпадёт с колонкой (col) на которой нажата кнопка на выходе рядка появится низкий уровень. Для реализации такого процесса нужно написать дешифратор (пример реализации модуля так же описан в данной статье [6]).
Сам модуль имеет вид:
module kypd_decoder(
input i_clk,
input i_rst_n,
input [3:0] i_row,
output reg [3:0] o_col,
output reg [3:0] o_number
);
reg [19:0] counter;
reg [3:0] col;
reg [3:0] row;
// row col
parameter ZERO = 8'b11100111,
ONE = 8'b01110111,
TWO = 8'b01111011,
THREE = 8'b01111101,
FOUR = 8'b10110111,
FIVE = 8'b10111011,
SIX = 8'b10111101,
SEVEN = 8'b11010111,
EIGHT = 8'b11011011,
NINE = 8'b11011101,
A = 8'b01111110,
B = 8'b10111110,
C = 8'b11011110,
D = 8'b11101110,
E = 8'b11101101,
F = 8'b11101011;
always @(posedge i_clk or negedge i_rst_n)
if (i_rst_n == 0)
counter <= 20'b0;
else
counter <= counter + 1'b1;
always @(posedge i_clk or negedge i_rst_n)
if (i_rst_n == 1'b0) begin
o_col <= 4'b1110;
col <= 4'b1110;
row <= 4'b1111;
end else if (!counter) begin
o_col <= {o_col [0], o_col [3:1]};
col <= o_col;
row <= i_row;
end
always @(posedge i_clk or negedge i_rst_n)
if (i_rst_n == 0)
o_number <= 4'b0;
else
case ({row, col})
ZERO: o_number <= 4'h0;
ONE: o_number <= 4'h1;
TWO: o_number <= 4'h2;
THREE: o_number <= 4'h3;
FOUR: o_number <= 4'h4;
FIVE: o_number <= 4'h5;
SIX: o_number <= 4'h6;
SEVEN: o_number <= 4'h7;
EIGHT: o_number <= 4'h8;
NINE: o_number <= 4'h9;
A: o_number <= 4'hA;
B: o_number <= 4'hB;
C: o_number <= 4'hC;
D: o_number <= 4'hD;
E: o_number <= 4'hE;
F: o_number <= 4'hF;
endcase
endmodule
Схема модуля в Vivado будет иметь вид:
Если кратко, то добавить модуль дешифратора в проект Vivado нужно так: Add Sources -> Add or create design sources -> Next -> Create File -> (написать имя файла) -> Ok -> Ok -> Yes. Создан пустой Verilog файл, после создания файла, нужно его найти в иерархии системы MIPSfpga-plus, написать код дешифратора и сохранить. Более подробное описание как добавить модуль в проект и просто как работать с Vivado описано в предыдущей моей статье:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1 [2]
Теперь приступим к подключению входов и выходов к шине AHB-Lite и физическим выходам нашей платы.
Иерархия mipsfpga_ahb имеет вид:
Для начала в директории Verilog Header mfp_ahb_lite_matrix_config.vh пропишем с помощью директивы `define название периферии которую будем подключать. Для этого найдем строку с идентификатором добавления в систему датчика освещённости (подробнее о датчике описано в предыдущей статье):
Строку нужно закомментировать, это позволит выключить все строки которые связаны с кодом подключения датчика освещённости к шине AHB-Lite:
//`define MFP_DEMO_LIGHT_SENSOR
Пропишем и расскоментируем строку для нащей периферии:
`define MFP_PMOD_KYPD
Откроем «mfp_system» найдем строки подключения екземпляра датчика освещенности:
`ifdef MFP_DEMO_LIGHT_SENSOR
И рядом добавим екземпляр своего модуля дешифратора:
`ifdef MFP_PMOD_KYPD
kypd_decoder kypd_decoder
(
.i_clk ( SI_ClkIn ),
.i_rst_n ( KEY_0 ),
.o_col ( KYPD_DATA [3:0] ),
.i_row ( KYPD_DATA [7:4] ),
.o_number ( KYPD_OUT )
);
`endif
Сигналы модуля дешифратора нужно подключить к екземпляру шины mfp_ahb_lite_matrix_with_loader (где прописывать нужные строчки можно смотреть по примеру интеграции датчика освещённости с помощью поиска по модулю MFP_DEMO_LIGHT_SENSOR):
`ifdef MFP_PMOD_KYPD
.KYPD_OUT ( KYPD_OUT ),
`endif
Для соединения экземпляров модуля дешифратора и шины добавим сигнал типа wire:
`ifdef MFP_PMOD_KYPD
wire [3:0] KYPD_OUT;
`endif
После подключения нашего модуля дешифратора к шине перейдём в «mfp_ahb_lite_matrix_with_loader» который находится по иерархии ниже модуля «mfp_system» и добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
input [3:0] KYPD_OUT,
`endif
Так же добавим эти сигналы в екземпляр «mfp_ahb_lite_matrix»:
`ifdef MFP_PMOD_KYPD
.KYPD_OUT ( KYPD_OUT ),
`endif
Те же действия проделаем в «mfp_ahb_lite_matrix» который находится по иерархии ниже модуля «mfp_ahb_lite_matrix_with_loader» и добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
input [3:0] KYPD_OUT,
`endif
Так же добавим эти сигналы в екземпляр «mfp_ahb_gpio_slave»:
`ifdef MFP_PMOD_KYPD
.KYPD_OUT ( KYPD_OUT ),
`endif
Перейдем в модуль «mfp_ahb_gpio_slave», это именно тот блок (GPIO) в который мы так рвались, добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
input [3:0] KYPD_OUT,
`endif
Теперь следует изменить модуль «mfp_ahb_gpio_slave» так, чтобы он обнаруживал адрес ввода/вывода с отображением в память (которые мы ещё определим) и записывал данные (HWDATA) в соответствующий обнаруженному адресу регистр:
`ifdef MFP_PMOD_KYPD
`MFP_PMOD_KYPD_IONUM : HRDATA <= { 28'b0, KYPD_OUT };
`endif
Чтобы указать адрес по которому мы будем обращаться, откроем заголовочный файл «mfp_ahb_lite_matrix_config.vh» и добавим:
`ifdef MFP_PMOD_KYPD
`define MFP_PMOD_KYPD_ADDR 32'h1f800018
`endif
Модуль GPIO использует младшие биты адреса, чтобы определить, с каким периферийным устройством следует осуществлять операцию чтения или записи информации.
`ifdef MFP_PMOD_KYPD
`define MFP_PMOD_KYPD_IONUM 4'h6
`endif
Вернемся назад по иерархии в модуль «mfp_system» и добавим порты ввода/вывода:
`ifdef MFP_PMOD_KYPD
inout [7:0] KYPD_DATA,
input KEY_0,
`endif
Стоит заметить что это уже не совсем те порты которые мы подключали к шине. Перейдем в топ модуль оболочку (у меня «cmoda7») и добавим в екземпляр «mfp_system» строчки:
`ifdef MFP_PMOD_KYPD
.KYPD_DATA ( JA ),
.KEY_0 ( ~ i_btn1 ),
`endif
Таким образом мы добавили к JA[7:0] выводам модуль нашего декодера и соединили декодер с процессором по шине AHB-Lite.
В нашем случае порты ввода/вывода JA в модуле оболочке и в файле ограничений (у меня «cmoda7.xdc») добавлять не потребуется так как они уже использовались для датчика освещённости. Но в других случаях такие действия потребуются, потому для понимания я просто покажу эти строки:
module cmoda7
(
...
...
...
inout [ 7:0] JA
);
## Pmod Header JA
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {JA[0]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {JA[1]}]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports {JA[2]}]
set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {JA[3]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {JA[4]}]
set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS33} [get_ports {JA[5]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {JA[6]}]
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports {JA[7]}]
И если мы вспомним в «mfp_ahb_lite_matrix_config.vh» мы закомментировали строку:
//`define MFP_DEMO_LIGHT_SENSOR
тем самым при синтезе системы весь код прописаный между
`ifdef MFP_DEMO_LIGHT_SENSOR
...
`endif
будет игнорироваться, и конфликтов использования портов не будет.
Мы можем посмотреть схему созданой системы MIPSfpga-plus со встроенным дешифратором для нашей клавиатуры, для этого откройте во вкладке RTL Analysys -> Open Elaborated Design -> Schematic. Здесь отображается вся схема системы, чтобы проверить правильность подключёного модуля дешифратора желательно пройтись по RTL Netlist и проверить все контакты.
Теперь можно сгенерировать bitstream файл (.bit) и загрузить в FPGA.
Напишем простую программу для взаимодействия клавиатуры и процессора.
Для загрузки кода в систему нужно перейти в папку скачаного mipsfpga plus ->github->mipsfpga-plus->programs->01_pmod_kypd откроем «mfp_memory_mapped_registers.h»
#define MFP_PMOD_KYPD_ADDR 0xBF800018
и
#define MFP_PMOD_KYPD (* (volatile unsigned *) MFP_PMOD_KYPD_ADDR )
далее откроем main.c и напишем пару строк для демонстрации:
#include "mfp_memory_mapped_registers.h"
int main ()
{
int n = 0;
for (;;)
{
MFP_7_SEGMENT_HEX = MFP_PMOD_KYPD;
}
return 0;
}
После в папке находим скрипт который компилирует код:
02_compile_and_link
Генерируем motorola_s_record файл:
08_generate_motorola_s_record_file
Проверяем к какому СОМ порту подключен USB UART преобразователь:
11_check_which_com_port_is_used
Изменяем файл 12_upload_to_the_board_using_uart:
set a=7
mode com%a% baud=115200 parity=n data=8 stop=1 to=off xon=off odsr=off octs=off dtr=off rts=off idsr=off type program.rec >.COM%a%
где а – номер СОМ порта, к которому подключен USB UART преобразователь.
И загружаем программу:
12_upload_to_the_board_using_uart
Результат:
В следующей части расскажу как добавить в MIPSfpga встроеный в cmoda7 АПЦ, и LCD дисплей от Nokia 5100.
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3 [7]
Автор: oleh_plotnikov
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/uart/256661
Ссылки в тексте:
[1] инструкция по скачиванию: http://www.silicon-russia.com/2015/12/11/mipsfpga-download-instructions/
[2] как портировать MIPSfpga-plus на другие платы: https://habrahabr.ru/post/329808/
[3] habrahabr.ru/post/275215: https://habrahabr.ru/post/275215/
[4] подробная документация: https://github.com/zhelnio/memos/blob/master/public/02_mips_uart/doc/D2_MicroAptiv_UP_AHB_Lite_Interface_MD01082.pdf
[5] даташит: https://reference.digilentinc.com/_media/reference/pmod/pmodkypd/pmodkypd_rm.pdf
[6] статье: https://habrahabr.ru/post/323360/
[7] Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3: https://habrahabr.ru/post/329854/
[8] Источник: https://habrahabr.ru/post/329852/
Нажмите здесь для печати.