Корзина

0 Товары - 0.00 RUB
В корзину

Курсы Валют

Курсы Валют  Дата ЦБ
Нал.USD
19.01 56.76
Нал.EUR
19.01 69.26
Нал.CNY
19.01 88.35

Оплата

visa

Реклама

Блог

Первый проект для VE-XC6SLX9. Часть 3.

В третьей части проекта для нашей платы VE-XC6SLX9 мы создадим видеоигру. За основу возьмем проект VGA sprites, уже упоминавшегося Arlet`a. В основу этого дизайна заложена идея генрации меняющихся спрайтов, в зависимости от положения счетчиков VGA развертки по горизонтали и вертикали. В состав проекта входят следующие файлы:

  • sprites_demo.v - модуль верхнего уровня, выполняет вывод и управление спрайтами
  • vga.v - генератор VGA сигналов
  • hardware_sprite.v - генератор спрайтов
  • tester.v - тесты

 Самым интересным файлом является hardware_sprite.v, рассмотрим его подробнее:

Verilog Code:
  1. /*
  2.  * Hardware Sprite and Supporting Modules
  3.  *
  4.  * by Brendan Doms, Sean McBride, Brian Shih, and Mikell Taylor
  5.  * (Olin College - Computer Architecture - Fall 2005)
  6.  *
  7.  */
  8.  
  9.  
  10. module hardware_sprite(Reset, R, G, B, A, clk, pclk, row, col, active, posx, posy, fliph, flipv, color);
  11.  
  12. input active, fliph, flipv, clk, pclk;
  13. input [9:0] col, posx;
  14. input [8:0] row, posy;
  15. input color, Reset;
  16. output R, G, B, A;
  17.  
  18. wire sR, sG, sB, sA;
  19. reg [3:0] xcoord, ycoord;
  20. reg [2:0] shape;
  21. reg [22:0] shapecounter;
  22. reg drawing;
  23.  
  24. parameter
  25. WIDTH = 10'd16,
  26. HEIGHT = 10'd16;
  27.  
  28. sprite_memory spritemem0 (Reset, sR, sG, sB, sA, clk, pclk, xcoord, ycoord, shape);
  29.  
  30. and a0 (R, sR, drawing);
  31. and a1 (G, sG, drawing);
  32. and a2 (B, sB, drawing);
  33. and a3 (A, sA, drawing);
  34.  
  35. // Initialize values
  36. always @(posedge clk) begin
  37. if (Reset) begin
  38. // Initialize things
  39. shapecounter = 0;
  40. if (color == 0)
  41. shape = 0;
  42. else if (color == 1)
  43. shape = 2;
  44. end
  45. else begin
  46. // Change the shape
  47. shapecounter = shapecounter + 1;
  48. if (shapecounter == 0) begin
  49. if (shape == 0)
  50. shape = 1;
  51. else if (shape == 1)
  52. shape = 0;
  53. else if (shape == 2)
  54. shape = 3;
  55. else if (shape == 3)
  56. shape = 2;
  57. end
  58. end
  59. end
  60.  
  61. always @(posedge pclk) begin
  62. drawing = (active && (col >= posx) && (col < posx + WIDTH) && (row >= posy) && (row < posy + HEIGHT));
  63. // Make sure NEXT pixel is being requested
  64. xcoord = col-posx+1;
  65. // Current row requested
  66. ycoord = row-posy;
  67. end
  68.  
  69. endmodule
  70.  
  71. // Video selector, essentially a 3 bit mux
  72. module video_selector(ROut, GOut, BOut, RIn, GIn, BIn, R, G, B, A);
  73.  
  74. output ROut, GOut, BOut;
  75. input RIn, GIn, BIn, R, G, B, A;
  76.  
  77. Mux2 mR (ROut, RIn, R, A);
  78. Mux2 mG (GOut, GIn, G, A);
  79. Mux2 mB (BOut, BIn, B, A);
  80.  
  81. endmodule
  82.  
  83. module Mux2 (OUT, A, B, S);
  84. // OUT=A if S=0, OUT=B if S=1
  85. output OUT;
  86. input A, B, S;
  87. wire notS, andA, andB;
  88.  
  89. not Inv0 (notS, S);
  90. and And0 (andA, A, notS);
  91. and And1 (andB, B, S);
  92. or Or1 (OUT, andA, andB);
  93. endmodule
  94.  
  95. // 16x16 sprite memory, has 6 shapes saved
  96. module sprite_memory(Reset, R, G, B, A, clk, pclk, xcoord, ycoord, shape);
  97.  
  98. input [3:0] xcoord, ycoord;
  99. input [2:0] shape;
  100. input clk, pclk, Reset;
  101. output R, G, B, A;
  102.  
  103. reg R, G, B, A;
  104. reg [63:0] shaperow;
  105.  
  106. // Sprite Shape 1 (Red Ghost 1)
  107. reg [63:0] shape1mem[15:0];
  108.  
  109. // Sprite Shape 2 (Red Ghost 2)
  110. reg [63:0] shape2mem[15:0];
  111.  
  112. // Sprite Shape 3 (Cyan Ghost 1)
  113. reg [63:0] shape3mem[15:0];
  114.  
  115. // Sprite Shape 4 (Cyan Ghost 2)
  116. reg [63:0] shape4mem[15:0];
  117.  
  118. // Initialize
  119. always @(posedge clk) begin
  120. if (Reset) begin
  121. // Initialize shape 1
  122. shape1mem[0] = 64'b0000000000000000100110011001100110011001100110010000000000000000;
  123. shape1mem[1] = 64'b0000000000001001100110011001100110011001100110011001000000000000;
  124. shape1mem[2] = 64'b0000000010011001100110011001100110011001100110011001100100000000;
  125. shape1mem[3] = 64'b0000100110011001111111111001100110011001111111111001100110010000;
  126. shape1mem[4] = 64'b1001100110011111111111111111100110011111111111111111100110011001;
  127. shape1mem[5] = 64'b1001100110011111001111111111100110011111001111111111100110011001;
  128. shape1mem[6] = 64'b1001100110011111001111111111100110011111001111111111100110011001;
  129. shape1mem[7] = 64'b1001100110011001001111111001100110011001001111111001100110011001;
  130. shape1mem[8] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  131. shape1mem[9] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  132. shape1mem[10] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  133. shape1mem[11] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  134. shape1mem[12] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  135. shape1mem[13] = 64'b1001100110010000100110011001100110010000100110011001100110010000;
  136. shape1mem[14] = 64'b1001100100000000000010011001100100000000000010011001100100000000;
  137. shape1mem[15] = 64'b1001000000000000000000001001000000000000000000001001000000000000;
  138. // Initialize shape 2
  139. shape2mem[0] = 64'b0000000000000000100110011001100110011001100110010000000000000000;
  140. shape2mem[1] = 64'b0000000000001001100110011001100110011001100110011001000000000000;
  141. shape2mem[2] = 64'b0000000010011001100110011001100110011001100110011001100100000000;
  142. shape2mem[3] = 64'b0000100110011001111111111001100110011001111111111001100110010000;
  143. shape2mem[4] = 64'b1001100110011111111111111111100110011111111111111111100110011001;
  144. shape2mem[5] = 64'b1001100110011111001111111111100110011111001111111111100110011001;
  145. shape2mem[6] = 64'b1001100110011111001111111111100110011111001111111111100110011001;
  146. shape2mem[7] = 64'b1001100110011001001111111001100110011001001111111001100110011001;
  147. shape2mem[8] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  148. shape2mem[9] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  149. shape2mem[10] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  150. shape2mem[11] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  151. shape2mem[12] = 64'b1001100110011001100110011001100110011001100110011001100110011001;
  152. shape2mem[13] = 64'b0000100110011001100110010000100110011001100110010000100110011001;
  153. shape2mem[14] = 64'b0000000010011001100100000000000010011001100100000000000010011001;
  154. shape2mem[15] = 64'b0000000000001001000000000000000000001001000000000000000000001001;
  155. // Initialize shape 3
  156. shape3mem[0] = 64'b0000000000000000011101110111011101110111011101110000000000000000;
  157. shape3mem[1] = 64'b0000000000000111011101110111011101110111011101110111000000000000;
  158. shape3mem[2] = 64'b0000000001110111011101110111011101110111011101110111011100000000;
  159. shape3mem[3] = 64'b0000011101110111111111110111011101110111111111110111011101110000;
  160. shape3mem[4] = 64'b0111011101111111111111111111011101111111111111111111011101110111;
  161. shape3mem[5] = 64'b0111011101111111001111111111011101111111001111111111011101110111;
  162. shape3mem[6] = 64'b0111011101111111001111111111011101111111001111111111011101110111;
  163. shape3mem[7] = 64'b0111011101110111001111110111011101110111001111110111011101110111;
  164. shape3mem[8] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  165. shape3mem[9] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  166. shape3mem[10] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  167. shape3mem[11] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  168. shape3mem[12] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  169. shape3mem[13] = 64'b0111011101110000011101110111011101110000011101110111011101110000;
  170. shape3mem[14] = 64'b0111011100000000000001110111011100000000000001110111011100000000;
  171. shape3mem[15] = 64'b0111000000000000000000000111000000000000000000000111000000000000;
  172. // Initialize shape 4
  173. shape4mem[0] = 64'b0000000000000000011101110111011101110111011101110000000000000000;
  174. shape4mem[1] = 64'b0000000000000111011101110111011101110111011101110111000000000000;
  175. shape4mem[2] = 64'b0000000001110111011101110111011101110111011101110111011100000000;
  176. shape4mem[3] = 64'b0000011101110111111111110111011101110111111111110111011101110000;
  177. shape4mem[4] = 64'b0111011101111111111111111111011101111111111111111111011101110111;
  178. shape4mem[5] = 64'b0111011101111111001111111111011101111111001111111111011101110111;
  179. shape4mem[6] = 64'b0111011101111111001111111111011101111111001111111111011101110111;
  180. shape4mem[7] = 64'b0111011101110111001111110111011101110111001111110111011101110111;
  181. shape4mem[8] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  182. shape4mem[9] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  183. shape4mem[10] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  184. shape4mem[11] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  185. shape4mem[12] = 64'b0111011101110111011101110111011101110111011101110111011101110111;
  186. shape4mem[13] = 64'b0000011101110111011101110000011101110111011101110000011101110111;
  187. shape4mem[14] = 64'b0000000001110111011100000000000001110111011100000000000001110111;
  188. shape4mem[15] = 64'b0000000000000111000000000000000000000111000000000000000000000111;
  189. end
  190. end
  191.  
  192. // Assign signals to proper outputs
  193. always @(posedge pclk) begin
  194. if (shape == 0)
  195. shaperow = shape1mem[ycoord];
  196. if (shape == 1)
  197. shaperow = shape2mem[ycoord];
  198. if (shape == 2)
  199. shaperow = shape3mem[ycoord];
  200. if (shape == 3)
  201. shaperow = shape4mem[ycoord];
  202. R = shaperow[(xcoord*4)+3];
  203. G = shaperow[(xcoord*4)+2];
  204. B = shaperow[(xcoord*4)+1];
  205. A = shaperow[xcoord*4];
  206. end
  207.  
  208. endmodule

Основным модулем здесь является module sprite_memory(Reset, R, G, B, A, clk, pclk, xcoord, ycoord, shape). Его основной задачей является формирование сигналов цветов R, G и B в зависимости от координат X и Y а также типа спрайта (shape). Сам спрайт формируется с помощью модуля sprite_memory(Reset, R, G, B, A, clk, pclk, xcoord, ycoord, shape). Далее для наглядности сформируем символ из модуля sprites_demo, разместим его на схему и заодно инвертируем сигнал Reset:

308fd8f87d3b300f535d65ff258afde5.jpg

На следующем шаге сопоставим сигналы проекта с реальными выводами FPGA:

4350dc68559bfa7ec1ccd9a2123e1757.jpg

 

После компиляции проекта и заливки в нашу отладочную плату, можно уже увидеть изображение на мониторе. Остался последний шаг, прикрутить к нашей FPGA управление от контроллера. В первой части проекта мы создали USB HID устройство, которым можно управлять с компьютера. Честно говоря фирменная программа от NXP нас не устроила (хотя бы по тому что она без исходников). Самым лучшим выход нам показалось создать программу в QT5 с использованием библиотеки HIDAPI

HIDAPI это многоплатформенная библиотека, которая позволяет писать приложения (ПО хоста USB) с доступом к интерфейсам устройств USB и Bluetooth HID-Class на операционных системахWindowsLinux и Mac OS X. В то время как эта библиотека может использоваться обмена данными со стандартными устройствами HID наподобие клавиатур, мышей и джойстиков, особенно полезное применение библиотеки - работа с пользовательскими (определенными производителем, Vendor-Defined) устройствами HID. Множество устройств работают так, что не требуется писать специальный драйвер для каждой платформы. HIDAPI просто интегрируется с клиентским приложением (ПО хоста), потому что нужно всего лишь подключить в проект файл исходного кода. На платформе Windows, HIDAPI также можно опционально использовать как функции в DLL.

Программы, которые используют HIDAPI, не нуждаются в драйверах. Это означает, что не требуется применять пользовательский драйвер для каждого устройства на каждой платформе.

HIDAPI предоставляет ясный и непротиворечивый программный интерфейс для каждой платформы (операционной системы), что делает простым написание приложений, которые обмениваются данными с устройствами USB HID, при этом нет необходимости вдаваться в детали библиотек HID и интерфейсов операционной системы на каждой платформе.

Исходный код HIDAPI также предоставляет тестовое GUI-приложение, которое может производить энумерацию и обмен данными с любым устройством HID, подключенным к операционной системе. Тестовое GUI компилируется и работает на всех платформах, поддерживаемых HIDAPI.

Как видите, практически идеальное решение ))) Приступим к созданию проекта. По большому счету все действия описываются в одном файле mainwindow.cpp:

C++ Code:
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3.  
  4. #include
  5. #include
  6. #include
  7. #include
  8.  
  9. #include
  10.  
  11.  
  12. #include "hidapi.h"
  13.  
  14. #define REPORT_LENGTH 255
  15.  
  16. //Объявление функций библиотеки
  17. typedef struct hid_device_info* (*HID_ENUMERATE)(unsigned short, unsigned short);
  18. typedef void (*HID_FREE_ENUMARATION)(struct hid_device_info*);
  19. typedef hid_device* (*HID_OPEN)(unsigned short, unsigned short, wchar_t*);
  20. typedef int (*HID_GET_MANUFACTURER_STRING)(hid_device *, wchar_t *, size_t);
  21. typedef int (*HID_GET_PRODUCT_STRING)(hid_device*, wchar_t*, size_t);
  22. typedef int (*HID_GET_SERIAL_NUMBER_STRING)(hid_device*, wchar_t*, size_t);
  23. typedef int (*HID_SET_NONBLOCKING)(hid_device*, int);
  24. typedef int (*HID_SEND_FEATURE_REPORT)(hid_device*, const unsigned char*, size_t);
  25. typedef int (*HID_GET_FEATURE_REPORT)(hid_device*, unsigned char*, size_t);
  26. typedef int (*HID_WRITE)(hid_device*, const unsigned char*, size_t);
  27.  
  28.  
  29. //Класс для работы с USB HID устройствами
  30. class hidControl
  31. {
  32. private:
  33. HID_OPEN hid_open;
  34. HID_SET_NONBLOCKING hid_set_nonblocking;
  35. HID_SEND_FEATURE_REPORT hid_send_feature_report;
  36. HID_GET_FEATURE_REPORT hid_get_feature_report;
  37. HID_GET_MANUFACTURER_STRING hid_get_manufacturer_string;
  38. HID_GET_PRODUCT_STRING hid_get_product_string;
  39. HID_ENUMERATE hid_enumerate;
  40. HID_FREE_ENUMARATION hid_free_enumeration;
  41. HID_WRITE hid_write;
  42.  
  43. public:
  44. hidControl()
  45. {}
  46.  
  47. ~hidControl()
  48. {}
  49.  
  50. unsigned char buf[REPORT_LENGTH];
  51. bool deviceFound;
  52. hid_device *handle;
  53. struct hid_device_info *devs, *cur_dev;
  54.  
  55. // Инициализация HID
  56. int init(unsigned int VID, unsigned int PID)
  57. {
  58. // Пробуем подключить библиотеку
  59. QString QString_str;
  60. QDir curdir;
  61. wchar_t wstr[255];
  62.  
  63. QLibrary lib(curdir.absolutePath() + "/hidapi");
  64.  
  65. lib.load();
  66.  
  67. if (!lib.isLoaded())
  68. return -1;
  69.  
  70. //Библиотека подключена можно вызывать функции библиотеки
  71. hid_open = (HID_OPEN)lib.resolve("hid_open");
  72. hid_set_nonblocking = (HID_SET_NONBLOCKING)lib.resolve("hid_set_nonblocking");
  73. hid_send_feature_report = (HID_SEND_FEATURE_REPORT)lib.resolve("hid_send_feature_report");
  74. hid_get_feature_report = (HID_GET_FEATURE_REPORT)lib.resolve("hid_get_feature_report");
  75. hid_get_manufacturer_string = (HID_GET_MANUFACTURER_STRING)lib.resolve("hid_get_manufacturer_string");
  76. hid_get_product_string = (HID_GET_PRODUCT_STRING)lib.resolve("hid_get_product_string");
  77. hid_enumerate = (HID_ENUMERATE)lib.resolve("hid_enumerate");
  78. hid_free_enumeration = (HID_FREE_ENUMARATION)lib.resolve("hid_free_enumeration");
  79. hid_write = (HID_WRITE)lib.resolve("hid_write");
  80.  
  81. //Переберем все USB HID устройства для отладки
  82. devs = hid_enumerate(0x00, 0x00);
  83. cur_dev = devs;
  84.  
  85. while (cur_dev)
  86. {
  87. qDebug() << "VID " << cur_dev->vendor_id << "PID " << cur_dev->product_id;
  88. cur_dev = cur_dev->next;
  89. }
  90. hid_free_enumeration(devs);
  91.  
  92. //Открываем нашу плату
  93. deviceFound = false;
  94. handle = hid_open(VID, PID, NULL);
  95.  
  96. if (handle)
  97. {
  98. //Если успешно открыли установим неблокирующий режим и выведем
  99. //строки производителя и устройства
  100. deviceFound = true;
  101. hid_set_nonblocking(handle, 1);
  102.  
  103. hid_get_manufacturer_string(handle, wstr, 255);
  104. QString_str = QString::fromStdWString(wstr);
  105. qDebug() << QString_str;
  106.  
  107. hid_get_product_string(handle, wstr, 255);
  108. QString_str = QString::fromStdWString(wstr);
  109. qDebug() << QString_str;
  110.  
  111. }
  112. else
  113. return -1;
  114.  
  115. return 0;
  116.  
  117.  
  118. }
  119.  
  120. int write()
  121. {
  122. if(deviceFound)
  123. {
  124. buf[0] = 1; // В первом байте находится номер репорта
  125. return hid_write(handle, buf, 65);
  126. }
  127. return -1;
  128. }
  129.  
  130. int read()
  131. {
  132. //Чтение нам пока не нужно
  133. return -1;
  134. }
  135.  
  136. };
  137.  
  138. hidControl *hid;
  139. unsigned char keys=0;
  140.  
  141. //Обработка нажатия клавиш---------------------------------------
  142. void MainWindow::keyPressEvent(QKeyEvent *event)
  143. {
  144.  
  145. if(event->key()==Qt::Key_Up)
  146. {
  147. ui->label->setText("up");
  148. keys=keys | 0x08;
  149. }
  150. else if(event->key()==Qt::Key_Down)
  151. {
  152. ui->label->setText("down");
  153. keys=keys | 0x01;
  154. }
  155. else if(event->key()==Qt::Key_Left)
  156. {
  157. ui->label->setText("left");
  158. keys=keys | 0x02;
  159. }
  160. else if(event->key()==Qt::Key_Right)
  161. {
  162. ui->label->setText("right");
  163. keys=keys | 0x04;
  164. }
  165.  
  166. hid->buf[1]=keys;
  167.  
  168. qDebug() << hid->write();
  169.  
  170. QMainWindow::keyPressEvent( event );
  171. }
  172.  
  173. //Обработка отпускания клавиш-------------------------------------------------------------------------------------
  174. void MainWindow::keyReleaseEvent(QKeyEvent *event)
  175. {
  176.  
  177. if(event->key()==Qt::Key_Up)
  178. {
  179. ui->label->setText("up");
  180. keys=keys & ~0x08;
  181. }
  182. else if(event->key()==Qt::Key_Down)
  183. {
  184. ui->label->setText("down");
  185. keys=keys & ~0x01;
  186. }
  187. else if(event->key()==Qt::Key_Left)
  188. {
  189. ui->label->setText("left");
  190. keys=keys & ~0x02;
  191. }
  192. else if(event->key()==Qt::Key_Right)
  193. {
  194. ui->label->setText("right");
  195. keys=keys & ~0x04;
  196. }
  197.  
  198. hid->buf[1]=keys;
  199.  
  200. qDebug() << hid->write();
  201.  
  202. QMainWindow::keyPressEvent( event );
  203. }
  204.  
  205. //Конструктор основного класса
  206. MainWindow::MainWindow(QWidget *parent) :
  207. QMainWindow(parent),
  208. ui(new Ui::MainWindow)
  209. {
  210. ui->setupUi(this);
  211.  
  212. hid = new hidControl();
  213.  
  214.  
  215. if(hid->init(0x1FC9, 0x0003)<0)
  216. {
  217. ui->label->setText("No device");
  218. qDebug() << "No device";
  219. }
  220. else
  221. {
  222. ui->label->setText("Start");
  223. qDebug() << "Start";
  224. }
  225.  
  226. }
  227.  
  228. //Деструктор основного класса
  229. MainWindow::~MainWindow()
  230. {
  231. delete ui;
  232. }

Тут в принципе ничего сложного нет. Все делает библиотека HIDAPI. От нас только требуется открыть наше устройство с VID=0x1FC9 и PID=0x0003, и если устройство открылось успешно, то можно управлять выводами нашего контролера по нажатиям на клавиатуре. Ну и по традиции видео и исходники:

Проект вывод спрайтов для FPGA: sprites_demo.zip

Проект управление по USB для PC: usb_hid_qt.zip

Перевод

Вход

Или классический вход:

Время

Карта сайта Визуальная электроника Полезные ссылки сайта Визуальная электроника