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

 

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

Автор: admin от 31-05-2017, 09:40, посмотрело: 273

В первой части я описал на примере cmoda7 как портировать MIPSfpga (Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1) на FPGA платы отличные от уже портированых среди которых такие популярные как: basys3, nexys4, nexys4_ddr фирмы Xilinx, а так же de0, de0_cv, de0_nano, de1, DE1, de10_lite, de2_115, DE2-115 фирмы Altera(Intel), во второй части как интегрировать клавиатуру Pmod KYPD (Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2).

В этой части добавим к MIPSfpga-plus встроенный АЦП, и популярный LCD от Nokia 5100.
С предыдущих частей можно сделать вывод, что интеграция периферии в MIPSFPGA состоит из пять основных этапов:

  • Добавление модуля интерфейса общения с периферией (i2c, spi, и т.д.).

  • Соединение входных/выходных портов модуля с шиной AHB-Lite.

  • Присваивание адресов сигналов подключаемого устройства.

  • Добавление констрейнов на физические контакты платы.

  • Написание программы для MIPS процессора.



Подключение встроенного в cmoda7 АЦП


Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3
Как я уже говорил плата cmodA7 имеет встроенный АЦП, pin 15 и 16 используются в качестве аналоговых входов модуля FPGA. Диапазон работы встроенного АЦП от 0-1V, поэтому используется внешняя схема для увеличения входного напряжения до 3.3V.
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3

Эта схема позволяет модулю XACD точно измерить любое напряжение от 0 В и 3,3 В (по отношению к GND). Чтобы работать с АЦП в Vivado существует блок IP (интеллектуальной собственности) Xilinx, с помощью которого можно будет просто его интегрировать в нашу систему MIPSfpga.

Добавление модуля


Откроем наш проект созданый в предыдущих частях (Часть 1 , Часть 2). Для начала нам нужно создать модуль взаимодействия IP с ситемой. В Vivado выполним Add source -> Add or create design sources -> Create file -> (назовем xadc) -> Finish -> Ok -> Yes. В разделе Source откроем файл.
Далее нам нужно добавить IP.
Во вкладке Project manager выбираем IP Catalog. Перейдем в папку FPGA Features and Design -> XADC -> XADC Wizard и откроем.
Следующим шагом будет настройка блока XADC. Во вкладке Basic установим значения как на изображении:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3
Если кратко то в этой вкладке мы установили частоту дискретизации, режим работы АЦП, и каналов.
Перейдем во вкладку ADC Setup:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3

Так как мы не будем использовать все сигналы предупреждений:
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3

Во вкладке Basic мы выбрали режим Single channel(так мы используем один канал VAux4):
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3

Жмем Ok -> Generate. После того как мы создали IP нужно его добавить в модуль xadc:
`timescale 1ns / 1ps

module xadc(    input i_clk,
                input i_rst_n,
                input i_xa_p,
                input i_xa_n,
                output reg [15:0] xadc_data
            );

wire [15:0] do_out;

xadc_wiz_0 wiz
             (
              .daddr_in(8'h14),    // Address bus for the dynamic reconfiguration port
              .dclk_in(i_clk),     // Clock input for the dynamic reconfiguration port
              .den_in(1'b1),       // Enable Signal for the dynamic reconfiguration port
              .di_in(16'b0),       // Input data bus for the dynamic reconfiguration port
              .dwe_in(1'b0),       // Write Enable for the dynamic reconfiguration port
              .vauxp4(i_xa_p),     // Auxiliary channel 4
              .vauxn4(i_xa_n),
              .busy_out(),         // ADC Busy signal
              .channel_out(),      // Channel Selection Outputs
              .do_out(do_out),     // Output data bus for dynamic reconfiguration port
              .drdy_out(),         // Data ready signal for the dynamic reconfiguration port
              .eoc_out(),          // End of Conversion Signal
              .eos_out(),          // End of Sequence Signal
              .alarm_out(),        // OR'ed output of all the Alarms    
              .vp_in(1'b0),        // Dedicated Analog Input Pair
              .vn_in(1'b0)
             );

always @(posedge i_clk, negedge i_rst_n)
if (!i_rst_n)
    xadc_data <= 16'b0;
else
    xadc_data <= do_out;

endmodule


Соединение входных/выходных портов модуля с шиной AHB-Lite


Пройдемся кратко по иерархии системы MIPSfpga и добавим нужные соединения:
В «mfp_system» добавим входные сигналы с модуля оболочки:
    `ifdef MFP_XADC
     input  I_XA_P,
     input  I_XA_N,
    `endif

сигнал типа wire для соединения экземпляров «xadc» и «mfp_ahb_lite_matrix_with_loader»:
    `ifdef MFP_XADC
     wire [15:0] XADC_DATA;
    `endif

    `ifdef MFP_XADC
     .XADC_DATA        (    XADC_DATA       ),
    `endif

И подключим сам екземпляр модуля xadc:
  `ifdef MFP_XADC
    xadc xadc
    (    
        .i_clk      (   SI_ClkIn  ),
        .i_rst_n    ( ~SI_Reset     ),
        .i_xa_p     (   I_XA_P      ),
        .i_xa_n     (   I_XA_N      ),
        .xadc_data  (   XADC_DATA   )
     );
    `endif

В «mfp_ahb_lite_matrix_with_loader»:
    `ifdef MFP_XADC
        input [15:0]     XADC_DATA,
    `endif

    `ifdef MFP_XADC
     .XADC_DATA        (    XADC_DATA       ),
    `endif

В «mfp_ahb_lite_matrix»:
    `ifdef MFP_XADC
     input [15:0]  XADC_DATA,
    `endif

   `ifdef MFP_XADC
    .XADC_DATA        (    XADC_DATA       ),
   `endif

В «mfp_ahb_gpio_slave» добавим выходной порт:
    `ifdef MFP_XADC
     input [15:0] XADC_DATA,
    `endif

и во второй always блок добавим на вход мультиплексора определяющего периферию:
    `ifdef MFP_XADC
     `MFP_XADC_IONUM  : HRDATA <= { 16'b0, XADC_DATA };
    `endif

Вернемся по иерархии в топ модуль оболочку, и добавим сигналы соединения с физическими контактами на плате:
    input         i_xa_p,
    input         i_xa_n,

и добавим в экземпляр «mfp_system»:
   `ifdef MFP_XADC
   .I_XA_P           (   i_xa_p         ),
   .I_XA_N           (   i_xa_n         ),
   `endif

Присваивание адресов сигналов подключаемого устройства


Присваивание адреса выполняется конфигурационном файле «mfp_ahb_litematrix_config.vh»:
Для начала добавим строчку комментируя//расскоментируя которую можно включать исключать написаные в проекте нами строки конкретной периферии определённой в данном случае `ifdef MFP_XADC… `endif:
`define MFP_XADC

определим адрес:
`ifdef MFP_XADC
`define MFP_XADC_ADDR               32'h1f80001C
`endif

А так же, константу определяющую адрес:
`ifdef MFP_XADC            
`define MFP_XADC_IONUM              4'h7
`endif

Добавление констрейнов на физические контакты платы


В файл *.xdc теперь нужно добавить созданные нами сигналы. Во встроенном АЦП платы cmodA7 у нас эти контакты имеют имя ADx_P — G2, и ADx_N — G3, добавим их в файл:
## Analog XADC Pins
set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports i_xa_n]
set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports i_xa_p]


Написание программы для MIPS процессора


Последним этапом является написание программы для процессора который будет взаимодействовать с АЦП.
Хочу подметить что основной целью статьи является демонстрация возможностей такого проекта как MIPSfpga, потому в коде всего пару строк. В какой то степени это и является точка отправления как для программистов которые решили выучить цифровой дизайн, так и дизайнеров которые решили больше углубится в программирование процессоров.
Гибкость состоит в том, что можно написать простейший модуль на Verilog(VHDL), и сложную програму на Си например реализовать SPI большим кодом, и наоборот.

Процессор MIPSfpga программируют с использованием инструментов разработки Codescape компании Imagination. Установите Codescape SDK и OpenOCD. Codescape поддерживает программирование как на языке C, так и на языке ассемблера.
Для загрузки кода в систему нужно перейти в папку скачаного mipsfpga plus ->github->mipsfpga-plus->programs->01_light_sensor откроем «mfp_memory_mapped_registers.h»
#define MFP_XADC_ADDR           0xBF80001С
и
#define MFP_XADC                (* (volatile unsigned *) MFP_XADC_ADDR          )

далее откроем main.c и напишем пару строк:
#include "mfp_memory_mapped_registers.h"

void delay();

int main ()
{
    int n = 0;

    for (;;)
    {
        MFP_7_SEGMENT_HEX = MFP_XADC  8 ;
		delay();
    }

    return 0;
}

void delay() {
  volatile unsigned int j;

  for (j = 0; j < (1000000); j++) ;	// delay 
}

Генерируем 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 на другие платы и интеграция периферии в систему. Часть 3
Таким образом, с АЦП в процессор поступает 16 битное число соответствующее напряжению поступающему на аналоговый вход на плате с делителя состоящего с резистора и фоторезистора, после чего процессор сдвигает данные на 8 бит в лево и выводит на семисегментный индикатор. Как видите все банально просто. Теперь можно дописывать код под наши потребности.


Интеграция LCD дисплея от Nokia 5100


В сети такой LCD дисплей среди ардуинщиков пользуется большим спросом, можно сказать они дали ему шанс на вторую жизнь применяя его в различных проектах. Поэтому и было принято решение попробовать его подключить к MIPS процессору в качестве практики.
Следующие действия я буду описывать кратко и по существу так, как все шаги подробно описаны выше.
Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3
Управление дисплеем осуществляется по интерфейсу SPI, дисплей является ведомым устройством. Однако, вместо обычных четырех линий управления здесь лишь три. Это линии тактирования CLK, выбора кристалла SCE и входных данных MOSI. Линия выхода MISO отсутствует. Это приводит к необходимости применять специальные методы управления, подробнее об этом далее. В Nokia 5110 присутствует также дополнительная линия управления Информация/Команда – D/C. Каждый байт, передаваемый в дисплей, может быть интерпретирован как команда или информационный байт, в зависимости от уровня на линии D/C.

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
































































PinОбозначение на дисплееОбозначение выходов в XDC файлеМаркировка контакта на
FPGA
Назначение
34BLo_sblW3Подсветка
33Clko_sckV2Сигнал синхронизации
32Dino_sdoW2Передача данных
30DCo_sdcT2Сигнал комманда/данные
29CEo_sceT1Сигнал разрешения передачи данных
28RSTo_rstR2Сигнал сброса
VCCVcc--Питание
GNDGnd--Земля


Добавление модуля интерфейса общения с периферией


Так как обратной связи с дисплеем не будет, можно написать модуль только на отправку данных. Даташит на дисплей Nokia 5100 LCD Display.
Напишем модуль для взаимодействия дисплея с MIPSfpga-plus и добавим его в проект.
/*
 * SPI interface for MIPSfpga
 */

module mfp_lcd_spi(
           input                                    clk,
           input                                    i_rst_n,
           input [7 : 0]                            value,
           input [2 : 0]                            ctrl,
           input                                    send,
           
           output    reg                            sdo,
           output                                   sck,
           output    reg                            ce,
           
           output    reg                            sdc,
           output    reg                            sbl,
           output    reg                            o_rst_n
           );

parameter DIV_WIDTH = 16;   // Width counter


reg [DIV_WIDTH - 1:0] counter;
reg [7:0]  data_r;
reg [3:0] bit_count_r;


// register for control signal
always @(posedge clk, negedge i_rst_n)
   if (!i_rst_n) begin

	   sdc     <= 1'b0;
       sbl     <= 1'b0;
	   o_rst_n <= 1'b0;

   end else begin

       sdc     <= ctrl[0];
       sbl     <= ctrl[1];
	   o_rst_n <= ctrl[2];

   end
//   
 

assign sck = (counter[DIV_WIDTH - 1]);


// counter for low frequency spi out
always @(posedge clk, negedge i_rst_n)
   if (!i_rst_n ) begin
	    counter <= {DIV_WIDTH{1'b0}};
   end else if (!ce)
	    counter <= counter + 1'b1;
   else 
	    counter <= {DIV_WIDTH{1'b0}};


// shift register for sending data
always @(posedge clk, negedge i_rst_n)
	if (!i_rst_n) begin

		data_r <= 8'b0;
		sdo <= 1'b0;
		bit_count_r <= 4'b1001;

	end else if (bit_count_r != 4'b1001 && counter == 0) begin
		
		sdo <= data_r[7];
		data_r <= data_r  1;
		bit_count_r <= bit_count_r + 1'b1;


	end else if (send && ce) begin
	
		data_r <= value; 
		bit_count_r <= 4'b0000;
	
	end
//

//control register for allow data transfer
always @(posedge clk, negedge i_rst_n)
	if (!i_rst_n) begin
		ce <= 1'b1;
	end else if (!send && bit_count_r == 4'b1001)
		ce <= 1'b1;
	else 
		ce <= 1'b0;
//		
		
endmodule

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

Соединение входных/выходных портов модуля с шиной AHB-Lite



Добавим в «mfp_system»:
    `ifdef MFP_LCD_5100       
     output                                  IO_CE,
     output                                  SDO,
     output                                  SCK,
     output                                  SDC,
     output                                  SBL,
     output                                  RST,
    `endif

     `ifdef MFP_LCD_5100
      wire [`MFP_LCD_5100_WIDTH      - 1:0] IO_LCD_5100;
      wire [`MFP_SEND_WIDTH          - 1:0] IO_SEND;
      wire [`MFP_CTRL_WIDTH          - 1:0] IO_CTRL;
     `endif

     `ifdef MFP_LCD_5100
     .IO_LCD_5100      (   IO_LCD_5100      ),
     .IO_SEND          (   IO_SEND          ),
     .IO_CE            (   IO_CE            ),
     .IO_CTRL          (   IO_CTRL          ),
     `endif

В «mfp_ahb_lite_matrix_with_loader»:
     `ifdef MFP_LCD_5100
      output [`MFP_LCD_5100_WIDTH      - 1:0] IO_LCD_5100,
      input  [`MFP_CE_WIDTH            - 1:0] IO_CE,
      output [`MFP_SEND_WIDTH          - 1:0] IO_SEND,
      output [`MFP_CTRL_WIDTH          - 1:0] IO_CTRL,
     `endif

      `ifdef MFP_LCD_5100
      .IO_LCD_5100      ( IO_LCD_5100     ),
      .IO_CE            ( IO_CE           ),
      .IO_SEND          ( IO_SEND         ),
      .IO_CTRL          ( IO_CTRL         ),
      `endif 

В «mfp_ahb_lite_matrix»:
      `ifdef MFP_LCD_5100
       output [`MFP_LCD_5100_WIDTH      - 1:0] IO_LCD_5100,
       input  [`MFP_CE_WIDTH            - 1:0] IO_CE,
       output [`MFP_SEND_WIDTH          - 1:0] IO_SEND,
       output [`MFP_CTRL_WIDTH          - 1:0] IO_CTRL,
      `endif     

      `ifdef MFP_LCD_5100 
      .IO_LCD_5100      ( IO_LCD_5100     ),
      .IO_CE            ( IO_CE           ),
      .IO_SEND          ( IO_SEND         ),
      .IO_CTRL          ( IO_CTRL         ),
      `endif

В «mfp_ahb_gpio_slave» добавим такие строки:
      `ifdef MFP_LCD_5100
       output reg [`MFP_LCD_5100_WIDTH      - 1:0] IO_LCD_5100,
       input      [`MFP_CE_WIDTH            - 1:0] IO_CE,
       output reg [`MFP_SEND_WIDTH          - 1:0] IO_SEND,
       output reg [`MFP_CTRL_WIDTH          - 1:0] IO_CTRL,
      `endif

      `ifdef MFP_LCD_5100 
       IO_LCD_5100     <= `MFP_LCD_5100_WIDTH'b0;
       IO_CTRL         <= `MFP_CTRL_WIDTH'b0;
       IO_SEND         <= `MFP_SEND_WIDTH'b0;
      `endif

      `ifdef MFP_LCD_5100
      
      `MFP_LCD_5100_IONUM      : IO_LCD_5100     <= HWDATA [`MFP_LCD_5100_WIDTH      - 1:0];
      `MFP_CTRL_IONUM          : IO_CTRL         <= HWDATA [`MFP_CTRL_WIDTH          - 1:0];
      `MFP_SEND_IONUM          : IO_SEND         <= HWDATA [`MFP_SEND_WIDTH          - 1:0];  
      `endif

`ifdef MFP_LCD_5100
`MFP_LCD_5100_IONUM: HRDATA <= { { 32 - `MFP_LCD_5100_WIDTH{ 1'b0 } } ,IO_LCD_5100         };
`MFP_CTRL_IONUM: HRDATA     <= { { 32 - `MFP_CTRL_WIDTH    { 1'b0  } } ,IO_CTRL};
`MFP_SEND_IONUM: HRDATA     <= { { 32 - `MFP_SEND_WIDTH    { 1'b0 } } ,IO_SEND};
`MFP_CE_IONUM: HRDATA       <= { { 32 - `MFP_CE_WIDTH      { 1'b0 } } ,IO_CE};
`endif

В топ модуль оболочку добавим выходные порты на плату:
    `ifdef MFP_LCD_5100
     output o_rst, 
            o_ce,
            o_sdc,
            o_sdo,
            o_sck,
            o_sbl,
    `endif

        `ifdef MFP_LCD_5100
        .IO_CE            (    o_ce          ),
        .SDO              (    o_sdo         ),
        .SCK              (    o_sck         ),
        .SDC              (    o_sdc         ),
        .SBL              (    o_sbl         ),
        .RST              (    o_rst         ),
        `endif

Присваивание адресов сигналов подключаемого устройства


В файл «mfp_ahb_lite_matrix_config.vh» добавим адреса и определения:
`define MFP_LCD_5100

`ifdef MFP_LCD_5100
`define MFP_LCD_5100_WIDTH          9
`define MFP_SEND_WIDTH              1
`define MFP_CE_WIDTH                1
`define MFP_CTRL_WIDTH              3
`endif

`ifdef MFP_LCD_5100
`define MFP_LCD_5100_ADDR           32'h1f800020
`define MFP_SEND_ADDR               32'h1f800024
`define MFP_CE_ADDR                 32'h1f800028
`define MFP_CTRL_ADDR               32'h1f80002C
`endif

`ifdef MFP_LCD_5100
`define MFP_LCD_5100_IONUM          4'h8
`define MFP_SEND_IONUM              4'h9
`define MFP_CE_IONUM                5'hA
`define MFP_CTRL_IONUM              5'hB        
`endif


Добавление констрейнов на физические контакты платы


Добавим выходы для дисплея в XDC файл:
### GPIO Pins 33 - 40 LCD
set_property -dict {PACKAGE_PIN W3 IOSTANDARD LVCMOS33} [get_ports o_sbl]
set_property -dict {PACKAGE_PIN V2 IOSTANDARD LVCMOS33} [get_ports o_sck]
set_property -dict {PACKAGE_PIN W2 IOSTANDARD LVCMOS33} [get_ports o_sdo]
set_property -dict {PACKAGE_PIN T2 IOSTANDARD LVCMOS33} [get_ports o_sdc]
set_property -dict {PACKAGE_PIN T1 IOSTANDARD LVCMOS33} [get_ports o_ce]
set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports o_rst]


Написание программы для MIPS процессора


В «mfp_memory_mapped_registers.h»:
#define MFP_LCD_5100_ADDR  		0xBF800020
#define MFP_SEND_ADDR   		0xBF800024
#define MFP_CE_ADDR      		0xBF800028
#define MFP_CTRL_ADDR    		0xBF80002C

#define value                   (* (volatile unsigned *) MFP_LCD_5100_ADDR      )
#define ctrl                    (* (volatile unsigned *) MFP_CTRL_ADDR          )
#define send                    (* (volatile unsigned *) MFP_SEND_ADDR          )
#define ce                      (* (volatile unsigned *) MFP_CE_ADDR            )

Напишем программу в main.c:

Загружаем и имеем простую заставку Imagination Technologies, дальше только фантазия.


Выражаю большую благодарность:
— Юрию Панчулу YuriPanchul за предоставление платы cmodA7.
— Евгению Короткому — доценту кафедры конструирования электронно-вычислительной аппаратуры факультета электроники, за предоставленную периферию и возможность посещать такое место как открытая лаборатория электроники Lampa.

Источник: Хабрахабр

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *