[Из песочницы] Подключение периферийных модулей к MIPSfpga, на примере клавиатуры Pmod KYPD
→ Описание клавиатуры найдете здесь
Pmod KYPD — 16-кнопочная клавиатура с цифрами в шестнадцатеричном формате (0-F). Опрос происходит способом поочередной подачи логического 0 на каждый столбец и считывания состояния строк. Если в момент опроса столбца одна из кнопок в нем нажата, соответствующая строка выдаст логическую 1.
Для начала необходимы исходники MIPSfpga.
→ Инструкция по скачиванию
Далее нужно скачать надстройку MIPSfpga-plus, которая позволяет записывать программы по UARTу.
Описание и инструкции по установке присутствуют, если коротко, то для того, чтобы была возможность просто запустить скрипт и проект собрался, необходимо:
— поместить исходники MIPSfpga в папку
C:\MIPSfpga;
, а MIPSfpga-plus по директории:
C:\github\mipsfpga-plus;
Далее в папке C:\github\mipsfpga-plus\boards выбрать свою плату, у меня это de0_cv, и выполнить скрипт make_project. Проект, который нужно запускать, будет находиться в C:\github\mipsfpga-plus\boards\de0_cv\project.
Если для вашей платы нет проекта, то можно выбрать наиболее подходящую по количеству логических ячеек и изменить назначения;
— Еще вам понадобятся компилятор, линковщик Codescape, а также USB-UART преобразователь, например, pl2303hx или ch340.
Подключение клавиатуры и USB-UART преобразователя к плате
Клавиатура напрямую будет подключена к шине AHB-Lite. Для интеграции клавиатуры в систему мы создали модуль decoder.v. Данный модуль работает по следующему принципу: каждую миллисекунду опрашивается один из столбцов и. если в этот момент была нажата кнопка в этом столбце. то соответствующая строка выдаст логическую 1. Каждой комбинации строка+столбец соответствует цифра от 0 до F. Данная цифра записывается в регистр и по шине передается в память процессора. С помощью программного обеспечения данные с памяти выводятся на индикатор.
input i_row1,
input i_row2,
input i_row3,
input i_row4,
input i_clk,
input i_rst_n,
output [3:0] o_col,
output [3:0] o_number);
reg [3:0] col;
reg [31:0] counter;
reg [3:0] number;
parameter ZERO = 8'b11100111; //row, col
parameter ONE = 8'b01110111;
parameter TWO = 8'b01111011;
parameter THREE = 8'b01111101;
parameter FOUR = 8'b10110111;
parameter FIVE = 8'b10111011;
parameter SIX = 8'b10111101;
parameter SEVEN = 8'b11010111;
parameter EIGHT = 8'b11011011;
parameter NINE = 8'b11011101;
parameter TEN = 8'b01111110;
parameter ELEVEN = 8'b10111110;
parameter TWELVE = 8'b11011110;
parameter THIRTEEN = 8'b11101110;
parameter FOURTEEN = 8'b11101101;
parameter FIFTEEN = 8'b11101011;
always @(posedge i_clk or negedge i_rst_n)
begin
if (i_rst_n == 1'b0)
begin
col <= 4'b1110;
end
else
begin
if (counter == 31'b111001001110000111000000)
begin
col <= {col [0], col [3:1]};
end
end
end
always @*
begin
if (i_rst_n == 0)
begin
number <= 4'b0;
end
else
begin
case ({i_row1, i_row2, i_row3, i_row4, col [0], col [1], col [2], col [3]})
ZERO:
begin
number <= 4'b0000;
end
ONE:
begin
number <= 4'b0001;
end
TWO:
begin
number <= 4'b0010;
end
THREE:
begin
number <= 4'b0011;
end
FOUR:
begin
number <= 4'b0100;
end
FIVE:
begin
number <= 4'b0101;
end
SIX:
begin
number <= 4'b0110;
end
SEVEN:
begin
number <= 4'b0111;
end
EIGHT:
begin
number <= 4'b1000;
end
NINE:
begin
number <= 4'b1001;
end
TEN:
begin
number <= 4'b1010;
end
ELEVEN:
begin
number <= 4'b1011;
end
TWELVE:
begin
number <= 4'b1100;
end
THIRTEEN:
begin
number <= 4'b1101;
end
FOURTEEN:
begin
number <= 4'b1110;
end
FIFTEEN:
begin
number <= 4'b1111;
end
default:
begin
number <= number;
end
endcase
end
end
always @(posedge i_clk or negedge i_rst_n)
begin
if (i_rst_n == 0)
begin
counter = 31'b0;
end
else
begin
if (counter == 31'b111001001110000111000011)
begin
counter = 31'b0;
end
else
begin
counter = counter + 1'b1;
end
end
end
assign o_number = number;
assign o_col = col;
endmodule
Подключаем к проекту файл с описанным выше модулем. В файле верхнего уровня, у нас это de0_cv.v, добавим следующие строчки:
`ifdef MFP_PMOD_KYPD
.KYPD_DATA ( GPIO_0 [35:28] ),
.KEY_0 ( KEY [0] )
`endif
Выделим ножки GPIO_0 [35], GPIO_0 [34] для питания клавиатуры. В файле mfp_system.v добавляем входы и выходы:
inout [7:0] KYPD_DATA,
input KEY_0
В описании модуля mfp_system добавим:
`ifdef MFP_PMOD_KYPD
wire [3:0] KYPD_OUT;
`endif
`ifdef MFP_PMOD_KYPD
decoder decoder
(
.i_clk ( SI_ClkIn ),
.i_rst_n ( KEY_0 ),
.i_row1 ( KYPD_DATA [6] ),
.i_row2 ( KYPD_DATA [4] ),
.i_row3 ( KYPD_DATA [2] ),
.i_row4 ( KYPD_DATA [0] ),
.o_col ( {KYPD_DATA [7],
KYPD_DATA [5],
KYPD_DATA [3],
KYPD_DATA [1]} ),
.o_number ( KYPD_OUT )
);
`endif
При создании экземпляра модуля mfp_ahb_lite_matrix_with_loader добавим в список входов наши данные:
`ifdef MFP_PMOD_KYPD
.KYPD_OUT ( KYPD_OUT ),
`endif
В файлах mfp_ahb_lite_matrix_with_loader.v, mfp_ahb_lite_matrix.v, mfp_ahb_gpio_slave.v добавляем вход:
input [3:0] KYPD_OUT
В файле mfp_ahb_lite_matrix_config.vh, который находится в папке C:\github\mipsfpga-plus, добавляем следующие строчки:
`define MFP_PMOD_KYPD_IONUM 4'h5
`define MFP_PMOD_KYPD_ADDR 32'h1f800014
Собственно, это и есть адреса, по которым будут доступны регистры. Последним штрихом будет написание программы, которая отображает числа на семисегментном индикаторе.
int main ()
{
int n = 0;
for (;;)
{
MFP_7_SEGMENT_HEX = MFP_PMOD_KYPD;
MFP_GREEN_LEDS = n++;
}
return 0;
}
Генерируем 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
Желаем успеха.