В первой части я описал на примере 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 состоит из пять основных этапов:
Как я уже говорил плата cmodA7 имеет встроенный АЦП, pin 15 и 16 используются в качестве аналоговых входов модуля FPGA. Диапазон работы встроенного АЦП от 0-1V, поэтому используется внешняя схема для увеличения входного напряжения до 3.3V.
Эта схема позволяет модулю 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 установим значения как на изображении:
Если кратко то в этой вкладке мы установили частоту дискретизации, режим работы АЦП, и каналов.
Перейдем во вкладку ADC Setup:
Так как мы не будем использовать все сигналы предупреждений:
Во вкладке Basic мы выбрали режим Single channel(так мы используем один канал VAux4):
Жмем Ok -> Generate. После того как мы создали IP нужно его добавить в модуль xadc:
Пройдемся кратко по иерархии системы MIPSfpga и добавим нужные соединения:
В «mfp_system» добавим входные сигналы с модуля оболочки:
сигнал типа wire для соединения экземпляров «xadc» и «mfp_ahb_lite_matrix_with_loader»:
И подключим сам екземпляр модуля xadc:
В «mfp_ahb_lite_matrix_with_loader»:
В «mfp_ahb_lite_matrix»:
В «mfp_ahb_gpio_slave» добавим выходной порт:
и во второй always блок добавим на вход мультиплексора определяющего периферию:
Вернемся по иерархии в топ модуль оболочку, и добавим сигналы соединения с физическими контактами на плате:
и добавим в экземпляр «mfp_system»:
Присваивание адреса выполняется конфигурационном файле «mfp_ahb_litematrix_config.vh»:
Для начала добавим строчку комментируя//расскоментируя которую можно включать исключать написаные в проекте нами строки конкретной периферии определённой в данном случае `ifdef MFP_XADC… `endif:
определим адрес:
А так же, константу определяющую адрес:
В файл *.xdc теперь нужно добавить созданные нами сигналы. Во встроенном АЦП платы cmodA7 у нас эти контакты имеют имя ADx_P — G2, и ADx_N — G3, добавим их в файл:
Последним этапом является написание программы для процессора который будет взаимодействовать с АЦП.
Хочу подметить что основной целью статьи является демонстрация возможностей такого проекта как 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»
далее откроем main.c и напишем пару строк:
Генерируем motorola_s_record файл:
Проверяем к какому СОМ порту подключен USB UART преобразователь:
Изменяем файл 12_upload_to_the_board_using_uart:
где а – номер СОМ порта, к которому подключен USB UART преобразователь.
И загружаем программу:
Схема подключения:
Таким образом, с АЦП в процессор поступает 16 битное число соответствующее напряжению поступающему на аналоговый вход на плате с делителя состоящего с резистора и фоторезистора, после чего процессор сдвигает данные на 8 бит в лево и выводит на семисегментный индикатор. Как видите все банально просто. Теперь можно дописывать код под наши потребности.
В сети такой LCD дисплей среди ардуинщиков пользуется большим спросом, можно сказать они дали ему шанс на вторую жизнь применяя его в различных проектах. Поэтому и было принято решение попробовать его подключить к MIPS процессору в качестве практики.
Следующие действия я буду описывать кратко и по существу так, как все шаги подробно описаны выше.
Управление дисплеем осуществляется по интерфейсу SPI, дисплей является ведомым устройством. Однако, вместо обычных четырех линий управления здесь лишь три. Это линии тактирования CLK, выбора кристалла SCE и входных данных MOSI. Линия выхода MISO отсутствует. Это приводит к необходимости применять специальные методы управления, подробнее об этом далее. В Nokia 5110 присутствует также дополнительная линия управления Информация/Команда – D/C?. Каждый байт, передаваемый в дисплей, может быть интерпретирован как команда или информационный байт, в зависимости от уровня на линии D/C?.
Схема подключения:
Так как обратной связи с дисплеем не будет, можно написать модуль только на отправку данных. Даташит на дисплей Nokia 5100 LCD Display.
Напишем модуль для взаимодействия дисплея с MIPSfpga-plus и добавим его в проект.
Временная диаграмма модуля SPI:
Добавим в «mfp_system»:
В «mfp_ahb_lite_matrix_with_loader»:
В «mfp_ahb_lite_matrix»:
В «mfp_ahb_gpio_slave» добавим такие строки:
В топ модуль оболочку добавим выходные порты на плату:
В файл «mfp_ahb_lite_matrix_config.vh» добавим адреса и определения:
Добавим выходы для дисплея в XDC файл:
В «mfp_memory_mapped_registers.h»:
Напишем программу в main.c:
Загружаем и имеем простую заставку Imagination Technologies, дальше только фантазия.
Выражаю большую благодарность:
— Юрию Панчулу YuriPanchul за предоставление платы cmodA7.
— Евгению Короткому — доценту кафедры конструирования электронно-вычислительной аппаратуры факультета электроники, за предоставленную периферию и возможность посещать такое место как открытая лаборатория электроники Lampa.
В этой части добавим к MIPSfpga-plus встроенный АЦП, и популярный LCD от Nokia 5100.
С предыдущих частей можно сделать вывод, что интеграция периферии в MIPSFPGA состоит из пять основных этапов:
- Добавление модуля интерфейса общения с периферией (i2c, spi, и т.д.).
- Соединение входных/выходных портов модуля с шиной AHB-Lite.
- Присваивание адресов сигналов подключаемого устройства.
- Добавление констрейнов на физические контакты платы.
- Написание программы для MIPS процессора.
Подключение встроенного в cmoda7 АЦП
Как я уже говорил плата cmodA7 имеет встроенный АЦП, pin 15 и 16 используются в качестве аналоговых входов модуля FPGA. Диапазон работы встроенного АЦП от 0-1V, поэтому используется внешняя схема для увеличения входного напряжения до 3.3V.
Эта схема позволяет модулю 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 установим значения как на изображении:
Если кратко то в этой вкладке мы установили частоту дискретизации, режим работы АЦП, и каналов.
Перейдем во вкладку ADC Setup:
Так как мы не будем использовать все сигналы предупреждений:
Во вкладке Basic мы выбрали режим Single channel(так мы используем один канал VAux4):
Жмем 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
Схема подключения:
Таким образом, с АЦП в процессор поступает 16 битное число соответствующее напряжению поступающему на аналоговый вход на плате с делителя состоящего с резистора и фоторезистора, после чего процессор сдвигает данные на 8 бит в лево и выводит на семисегментный индикатор. Как видите все банально просто. Теперь можно дописывать код под наши потребности.
Интеграция LCD дисплея от Nokia 5100
В сети такой LCD дисплей среди ардуинщиков пользуется большим спросом, можно сказать они дали ему шанс на вторую жизнь применяя его в различных проектах. Поэтому и было принято решение попробовать его подключить к MIPS процессору в качестве практики.
Следующие действия я буду описывать кратко и по существу так, как все шаги подробно описаны выше.
Управление дисплеем осуществляется по интерфейсу SPI, дисплей является ведомым устройством. Однако, вместо обычных четырех линий управления здесь лишь три. Это линии тактирования CLK, выбора кристалла SCE и входных данных MOSI. Линия выхода MISO отсутствует. Это приводит к необходимости применять специальные методы управления, подробнее об этом далее. В Nokia 5110 присутствует также дополнительная линия управления Информация/Команда – D/C?. Каждый байт, передаваемый в дисплей, может быть интерпретирован как команда или информационный байт, в зависимости от уровня на линии D/C?.
Схема подключения:
Pin | Обозначение на дисплее | Обозначение выходов в XDC файле | Маркировка контакта на FPGA |
Назначение |
---|---|---|---|---|
34 | BL | o_sbl | W3 | Подсветка |
33 | Clk | o_sck | V2 | Сигнал синхронизации |
32 | Din | o_sdo | W2 | Передача данных |
30 | DC | o_sdc | T2 | Сигнал комманда/данные |
29 | CE | o_sce | T1 | Сигнал разрешения передачи данных |
28 | RST | o_rst | R2 | Сигнал сброса |
VCC | Vcc | - | - | Питание |
GND | Gnd | - | - | Земля |
Добавление модуля интерфейса общения с периферией
Так как обратной связи с дисплеем не будет, можно написать модуль только на отправку данных. Даташит на дисплей 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:
Соединение входных/выходных портов модуля с шиной 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:
main.c
#include "mfp_memory_mapped_registers.h"
#include <stdlib.h>
void delay(int delay); // задержка
void waitTillLCDDone(); // ждём пока закончится передача
void init(); // инициализация дисплея
void start_image(); // загрузка картинки
void disp_picture(); //обновление картинки после загрузки
void gotoXY(int x, int y); // переход на нужные координаты
void send_byte(int command, int data); // отравка одного байта
void clear_disp(); // очистка дисплея
int main ()
{
init ();
start_image();
delay(1000);
}
void init(){
unsigned int lcd_cmd[7] = {0x21, 0x13, 0x04, 0xC0, 0x20, 0x0C, 0x08};
unsigned int i;
for (i=0; i<7; i++) {
send_byte(0x06, lcd_cmd[i]);
}
}
void start_image (){
unsigned int screen[504] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x07, 0x03, 0x83, 0x81, 0xC1, 0xC1, 0xE1, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC1, 0xC1, 0xC1, 0x83, 0x83, 0x07, 0x07, 0x0F, 0x1F, 0x1F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x03, 0x01, 0x00, 0x00, 0xE0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF0, 0xC0, 0x00, 0x00, 0x01, 0x07, 0x3F, 0xF3, 0xC3, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xC0, 0x80, 0x00, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x3F, 0x1F, 0x1F, 0x0F, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
unsigned int i;
gotoXY(0, 0);
for (i=0; i<504; i++) {
send_byte(0x7, screen[i]);
}
disp_picture();
for (i=0; i < 4; i++){
send_byte(0x06, 0x0D);
delay(1000);
send_byte(0x06, 0x0C);
delay(1000);
}
}
void send_byte(int command, int data){
ctrl = command;
value = data;
send = 1;
send = 0;
waitTillLCDDone();
waitTillLCDDone();
}
void waitTillLCDDone() {
do {
} while (!ce);
}
void disp_picture(){
send_byte(0x06, 0x0C);
}
void clear_disp(){
send_byte(0x06, 0x08);
}
void gotoXY(int x, int y)
{
send_byte(0x6, 0x80 | x); // Column.
send_byte(0x6, 0x40 | y); // Row. ?
}
void delay(int delay)
{
volatile unsigned int j;
delay = delay * 5000;
for (j = 0; j < (delay); j++) ; // delay
}
Загружаем и имеем простую заставку Imagination Technologies, дальше только фантазия.
Выражаю большую благодарность:
— Юрию Панчулу YuriPanchul за предоставление платы cmodA7.
— Евгению Короткому — доценту кафедры конструирования электронно-вычислительной аппаратуры факультета электроники, за предоставленную периферию и возможность посещать такое место как открытая лаборатория электроники Lampa.
Поделиться с друзьями
Serge78rus