Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2

в 3:39, , рубрики: Altera, fpga, imagination technologies, mips, MIPS microAptiv UP, MIPSfpga, SPI, uart, Verilog, vhdl, xilinx, Анализ и проектирование систем, ПЛИС, программирование микроконтроллеров

MIPSfpga микропроцессор MIPS32 microAptiv описаный на языке Verilog для образовательных целей фирмы Imagination, который имеет кэш-память и блок управления памятью. Код процессора доступен пользователю (инструкция по скачиванию) и может использоваться для моделирования и реализации процессора на FPGA плате.

Данная статья является продолжением статьи о том как портировать MIPSfpga-plus на другие платы, и в ней будет описано как интегрировать периферию в систему MIPSfpga:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 1

Так же о том как начать работать с MIPSfpga написано в статье:
habrahabr.ru/post/275215

Процессор использует интерфейс памяти для связи с периферийными устройствами. То есть, это означает что данные записываются и считываются с подключенной периферии так же, как и с блока памяти RAM. Интеграция периферии в процессор осуществляется подключением к шине AHB-Lite(подробная документация). Подробней попробуем разобраться в процессе подключения.

Для начала нужно иметь понятие как будут проходить сигналы по шине AHB-Lite:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 2

Видно, что процесс считывания данных с периферии осуществляется по сигналу HRDATA, передача данных производится по HWRITE с активным высоким уровнем на сигнале разрешения записи, выбор GPIO осуществляется выбором адреса на HADDR.

1. Подключение клавиатуры Digilent Pmod KYPD

Первым датчиком который был подключён это 16 кнопочный pmod KYPD (даташит)
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 3

Распиновка и сигналы клавиатуры описаны в таблице:

Пин Сигнал Назначение Пин Сигнал Назначение
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 контакт питания

схема подключения клавиатуры очень простая:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 4

Следующим шагом для интеграции клавиатуры к шине AHB-lite будет написание модуля на Verilog. На схеме показано что ряды подтянуты к питанию сопротивлениями в R=10к, это значит что активный сигнал на них будет низким, а на каждую колонку с определенной частотой подается тактовый сигнал (низкий уровень). В момент когда активный сигнал на входе совпадёт с колонкой (col) на которой нажата кнопка на выходе рядка появится низкий уровень. Для реализации такого процесса нужно написать дешифратор (пример реализации модуля так же описан в данной статье).

Сам модуль имеет вид:

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 будет иметь вид:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 5

Если кратко, то добавить модуль дешифратора в проект Vivado нужно так: Add Sources -> Add or create design sources -> Next -> Create File -> (написать имя файла) -> Ok -> Ok -> Yes. Создан пустой Verilog файл, после создания файла, нужно его найти в иерархии системы MIPSfpga-plus, написать код дешифратора и сохранить. Более подробное описание как добавить модуль в проект и просто как работать с Vivado описано в предыдущей моей статье:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1

Теперь приступим к подключению входов и выходов к шине AHB-Lite и физическим выходам нашей платы.

Иерархия mipsfpga_ahb имеет вид:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2 - 6

Для начала в директории 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
);
cmoda7.xdc

## 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

Автор: oleh_plotnikov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js