Pull to refresh

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

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

Данная статья является продолжением статьи о том как портировать MIPSfpga-plus на другие платы, и в ней будет описано как интегрировать периферию в систему MIPSfpga-plus на примере 16 кнопочной клавиатуры Digillent Pmod KYPD:



Подключение клавиатуры к процессору позволит пользователю общаться с ним. В общем 16 кнопочные клавиатуры бывают в различных представлениях, но реализация и принцип работы у них одинаковый. Поэтому, по даному примеру можно интегрировать и схожие клавиатуры.

Интеграция встроенного в плату АЦП, а так же подключения дисплея от Nokia 5100 описана в следующей части моего tutorial:

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

Так же о том как начать работать с MIPSfpga написано в статье.

Архитектура MIPS является одной из первых архитектур компьютеров с сокращенным набором команд (RISC). Она появилась в результате исследований в Стэнфордском университете в 1981 году и революционно увеличила эффективность компьютерных архитектур. Коммерческое применение архитектуры MIPS началось в 1984 году фирмой 2 MIPSfpga: Начало работы Imagination Technologies v1.3, 1 марта, 2016 MIPS Computer Systems, которая в 2013 году была приобретена компанией Imagination Technologies.

Процессоры MIPS использовались в высокопроизводительных рабочих станциях Silicon Graphics, которые производились в 1980 и 1990 годах. Первым коммерчески успешным продуктом был процессор MIPS R3000, который имел пятистадийный конвейер. За ним последовал R4000, в котором были добавлены 64-разрядные команды, суперскалярный R8000, процессор с внеочередным выполнением команд R10000 и множество других высокопроизводительных ядер.

Со временем архитектура MIPS эволюционировала для применений в недорогих изделиях с малым энергопотреблением, таких как бытовые электронные устройства, сетевое оборудование, микроконтроллеры. Семейство M4K базируется на классической 32-разрядной архитектуре с пятистадийным конвейером. В семействе M14K добавлен набор 16-разрядных инструкций microMIPS, что позволяет уменьшить размер программ для встраиваемых приложений, в которых очень важна стоимость. В семействе microAptiv набор инструкций M14K расширен дополнительными инструкциями цифровой обработки сигналов. Ядро M14K существует в двух вариантах: микроконтроллерном (UC) и микропроцессорном (UP). Микропроцессорный вариант содержит кэш-память и поддерживает виртуальную память, что обеспечивает возможность запуска операционной системы, такой как Linux или Android. Возможно, вы знакомы с популярной линейкой микроконтроллеров PIC32 фирмы Microchip, которая основана на архитектуре M4K.

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

Для начала нужно иметь понятие как будут проходить сигналы по шине AHB-Lite:


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

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


Первым датчиком который был подключён это 16 кнопочный pmod KYPD (даташит).



В моем случае для подключения клавиатуры был использован интерфейс Pmod, но можно использовать любые другие пины вашей платы, но тогда в файле с ограничениями *.xdc нужно будет их прописать. К каким пинам подключать клавиатуру описано ниже в таблице.

Распиновка и сигналы клавиатуры описаны в таблице:
Пин Сигнал Назначение Пин Сигнал Назначение
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.
Клавиатура использует 4 ряда и столбца для создания массива з 16 тактовых кнопок.

На схеме показано что ряды подтянуты к питанию сопротивлениями в 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 будет иметь вид:



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

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

Теперь приступим к подключению входов и выходов к шине 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
);

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
Tags:
Hubs:
+10
Comments 0
Comments Leave a comment

Articles