Блог

Формирование HDMI изображения с использованием NIOS II.

Для проверки основных систем нашей платы VE-10CL025 таких как FPGA, HDMI, SDRAM было решено создать проект, на основе процессорного ядра NIOS II. В нашем проектк процессор NIOS с помощью упрощенной библиотеки simple_graphics формирует изображение в экранном буфере, расположенном в SDRAM памяти. Далее данные из SDRAM считываются при помощи DMA, после чего передаются на блок генерации HDMI сигналов. Все компоненты системы, кроме блока генерации HDMI — стандартные (встроены в Quartus).Теперь подробнее о том, как это реализовать. Для начала нужно создать пустой проект в Quartus, сконфигурировать его под конкретную ПЛИС и создать систему SOPC. Более подробно это описано в нашей статье Процессор Nios II для VE-EP4CE10E.

Схема получившейся SOPC:

pic1

Рассмотрим компоненты, составляющие нашу SOPC:

Компонент clk_0 (Clock Source) Входной буфер для сигнала частоты и сброса.

Параметры компонента clk_0
СтраницаПараметрЗначениеЕдиницы
clock_source Clock frequency 50000000 Hz
clock_source Clock frequency is known Yes  
clock_source Reset synchronus edges Both  

Компоненты clk_bridge_0, clk_bridge_1, clk_bridge_0 (Clock Bridge) Выходные буферы частоты для SDRAM и HDMI.

Параметры clk_bridge_0:

Параметры компонента clk_bridge_0
СтраницаПараметрЗначениеЕдиницы
altera_clock_bridge Derived clock rate 120000000 Hz
altera_clock_bridge Explicit clock rate 0  
altera_clock_bridge Number of Clock Outputs 1  

Параметры clk_bridge_1:

Параметры компонента clk_bridge_1
СтраницаПараметрЗначениеЕдиницы
altera_clock_bridge Derived clock rate 40000000 Hz
altera_clock_bridge Explicit clock rate 0  
altera_clock_bridge Number of Clock Outputs 1  

Параметры clk_bridge_2:

Параметры компонента clk_bridge_2
СтраницаПараметрЗначениеЕдиницы
altera_clock_bridge Derived clock rate 200000000 Hz
altera_clock_bridge Explicit clock rate 0  
altera_clock_bridge Number of Clock Outputs 1  

Компоненты altpll_0 (ALTPLL Intel FPGA IP) синтезатор частоты для SOPC, SDRAM и HDMI.

Параметры компонента alt_pll_0
СтраницаПараметрЗначениеЕдиницы
c0 Clock rate 120000000 Hz
c0 Clock phase 0 Deg
c1 Clock rate 120000000 Hz
c1 Clock phase -60 Deg
c2 Clock rate 40000000 Hz
c2 Clock phase 0 Deg
c3 Clock rate 200000000 Hz
c2 Clock phase 0 Deg

Компонент nios2_gen2_0 (Nios II Processor) основной процессор системы.  окне настроек выбрать NiosII/f, остальные настройки описаны в таблице.

Параметры компонента nios2_gen2_0
СтраницаПараметрЗначениеЕдиницы
Main Nios II Core Nios II/f  
Reset Vector Reset vector memory onchip_memory2_0.s1  
Reset Vector Reset vector offset 0x00000000  
Reset Vector Reset vector 0x01008000  
Exeption Vector Exeption vector memory onchip_memory2_0.s1  
Exeption Vector Exeption vector offset 0x00000020  
Exeption Vector Exeption vector 0x01008020  
Fast TLB Miss Exeption Vector Fast TLB Miss Exeption vector memory nios2_gen2_0.debug_mem_slave  
Fast TLB Miss Exeption Vector Fast TLB Miss Exeption vector offset 0x00000040  
Fast TLB Miss Exeption Vector Fast TLB Miss Exeption vector 0x00000000  

Компонент jtag_usart_0 (JTAG UART Intel FPGA IP) интерфейс отладчика системы. Компонент, предназначенный для передачи данных из Nios в IDE (аналог semihosting в ARM). Полезен для отладки. 

Параметры компонента jtag_usart_0
СтраницаПараметрЗначениеЕдиницы
Write FIFA (Data from Avalon to JTAG Buffer depth (bytes) 64 bytes
Write FIFA (Data from Avalon to JTAG IRQ threshold 8  
Write FIFA (Data from Avalon to JTAG Constuct using registers No  
Read FIFA (Data from JTAG to Avalon Buffer depth (bytes) 64 bytes
Read FIFA (Data from JTAG to Avalon IRQ threshold 8  
Read FIFA (Data from JTAG to Avalon Constuct using registers No  

Компонент sysid_qsys_0 (System ID Peripheral Intel FPGA IP) индентификационный номер системы. По сути это порт-константа, которой при каждой сборке SOPC присваивается значение, указанное пользователем и временная метка. Компонент предназначен для защиты от программирования неправильно сконфигурированной SOPC системы. В настройках желательно ввести свое значение (произвольное).

Параметры компонента sysid_qsys_0
СтраницаПараметрЗначениеЕдиницы
altera_avalon_sysid_qsys 32 bit System ID 0x12345678  

Компонент onchip_memory2_0 (On-Chip Memory (RAAM or ROM)) Память программ встроенная в FPGA. Это ОЗУ процессора. Также здесь хранится сама программа процессора. В настройках памяти нужно установить размер ОЗУ — 32000 байт.

Параметры компонента onchip_memory2_0
СтраницаПараметрЗначениеЕдиницы
Memory type Type RAM (Writable)  
Memory type Block type Auto  
Size Slave S1 Data width 32 bit
Size Total memory size 32000 bytes

Компонент new_sdram_controller_0 (SDRAM Controller Intel FPGA IP) Контроллер SDRAM памяти. В данном случае в SDRAM будет размещаться видеобуфер. Настройки контроллера приведены в таблице.

Параметры компонента new_sdram_controller_0
СтраницаПараметрЗначениеЕдиницы
Data Width Bits 8  
Architecture Chip select 1  
Architecture Banks 4  
Address Width Row 12  
Address Width Column 10  
Timing Cas latency cycles 2  
Timing Initialization refresh cycles 8  
Timing Issue one refresh command every 7.8125 uS
Timing Delay after powerup, before initialization 200.0 uS
Timing Duration of refresh command (t_rfc) 70.0 nS
Timing Duration of precharge command (t_rp) 20.0 nS
Timing ACTIVE to READ or WRITE delay (t_rcd) 20.0 nS
Timing Access time (t_ac) 5.5 nS
Timing Write recovery time (t_wr, no auto precharge) 14.0 nS

Компонент video_pixel_buffer_dma_0 (Pixel Buffer DMA Controller) Контроллер видео памяти. Забирает данные из SDRAM посредством DMA, или прямого доступа к памяти, т.е. без участия основного процессора.

Параметры компонента clk_0
СтраницаПараметрЗначениеЕдиницы
Addressing Parameters Addressing Mode X-Y  
Addressing Parameters Default Buffer Start Address 0x00000000  
Addressing Parameters Default Back Buffer Start Address 0x00100000  
Frame Resolution Width (# of pixels) 400  
Frame Resolution Height (# of lines) 300  
Pixel Format Color Space 16-bit RGB  

Компонент video_rgb_resampler_0 (RGB Resampler) Преобразователь разрядности RGB шины. Преобразует данные цвета из 16 бит в 8.

Параметры компонента clk_0
СтраницаПараметрЗначениеЕдиницы
Parameters Incoming Format 16-bit RGB  
Parameters Outgoing Format 8-bit RGB  
Parameters Alpha Value for Output 1023  

Компонент video_scaler_0 (Scaler) Преобразователь разрешения видеокартинки. В нашем случае из точки размером 1 пикселя делает точку размером 2*2 пикселя.

Параметры компонента clk_0
СтраницаПараметрЗначениеЕдиницы
Scaling Parameters Width Scaling Factor 2  
Scaling Parameters Height Scaling Factor 2  
Incoming Frame Resolution Width (# of pixels) 400  
Incoming Frame Resolution Height (# of lines) 300  
Pixel Format Data Bits per Symbol 8  
Pixel Format Symbols per Beat 1  

Компонент video_dual_clock_buffer_0 (Dual-Clock FIFO) Синхронизация потоков данных, находящихся в разнык тактовых доменах. Это FIFO с двумя входами тактовой частоты. Так как частота процессора и видеосистемы различается, то для передачи данных в видеосистему нужен FIFO. Кроме того, он задерживает данные на время передачи синхроимпульсов. 

Параметры компонента video_dual_clock_buffer_0
СтраницаПараметрЗначениеЕдиницы
Pixel Format Color Bits 8  
Pixel Format Color Planes 1  

Компонент video_sync_generator_0 (Video Sync Generator Intel FPGA IP) Компонент, формирующий видеосигнал для HDMI. В частности, он формирует сигналы горизонтальной и вертикальной синхронизации, и управляет идущим на него потоком данных, приостанавливая его во время передачи синхроимпульсов.

Параметры компонента video_sync_generator_0
СтраницаПараметрЗначениеЕдиницы
Parameters Data Stream Bit Width 8  
Parameters Beats per Pixel 1  
Parameters Number of Columns 800  
Parameters Number of Rows 600  
Parameters Horizontal Blank Pixels 0  
Parameters Horizontal Front Porch Pixels 0  
Parameters Horizontal Sync Pulse Pixels 256  
Parameters Horizontal Sync Pulse Polarity 0  
Parameters Vertical Blank Lines 0  
Parameters Vertical Front Porch Lines 0  
Parameters Vertical Sync Pulse Lines 28  
Parameters Vertical Sync Pulse Polarity 0  
Parameters Total Horizontal Scan Pixels 1056  
Parameters Total Vertical Scan Lines 628  

Важно обратить внимание на поле clk. Видно, что на компоненты nios2_gen2_0, jtag_usart_0, sysid_qsys_0,onchip_memory2_0, new_sdram_controller_0, video_pixel_buffer_dma_0, video_rgb_resampler_0, video_scaller_0 подается тактовая частота с выхода PLL c0 (120 МГц). На элемент video_dual_clock_buffer_0 подается 2 частоты: первая на которой работает процессор, память и DMA frame буфер, это тактовая частота с выхода PLL c0 (120 МГц), и вторая это частота, на которй формируется видеоизображение 800*600@60 гц тактовая частота с выхода PLL c2 (40 МГц). Ну и на сам формирователь изображения video_sync_generator_0 подается тактовая частота с выхода PLL c2 (40 МГц).

Далее нужно найти в настройки процессора, и установить reset vector = onchip_memory2, offset = 0x0 и exception vector = onchip_memory2, offset = 0x20. Затем нужно выполнить команды System > Assign Base Addresses и File>Refresh System, после чего должны исчезнуть все сообщения об ошибках внизу окна. После этого кнопкой «Generate» нужно запустить сборку системы, перед этим сохранив ее.

После окончания сборки закрываем окно SOPC Builder. В Quartus создаем новый Block Diagram/Schematic File (BDF) и сохраняем его под каким-нибудь именем (у меня frame_buffer_top.bdf). В окне «Project Navigator» во вкладке «Files» находим frame_buffer_top.bdf и через контекстное меню вызываем команду «Set as Top-Level Entity». На самом поле схемы через контекстное меню вызываем команду Insert > Insert Symbol, и в разделе Project находим созданную систему SOPC и добавляем ее на схему. Дальше добавляем созданный нами SOPC и элементы, необходимые для генерации HDMI сигнала. Важно, чтоб параметры видеосигналов video_sync_generator_0 и генратора HDMI сигнала совпадали.

Схема получившейся системы:

pic2

Для формированя изображения используется модифицированная библиотека simple_graphics. В программе формируется три вида объектов: цветные круги, прямоугольная область для надписи и текстовая надпись. Изображение сначала формируется в дополнительном буфере, затем буфера переключаются, и точно такое-же изображение формируется в основном буфере.

Исходный код программы:

C++ Code:
  1. #include "main.h"
  2. #include "simple_gfx/simple_graphics.h"
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #include "system.h"
  7. #include "sys/alt_log_printf.h"
  8. #include "altera_up_avalon_video_pixel_buffer_dma.h"
  9.  
  10. int main(void)
  11. {
  12. unsigned int x1,y1,x2,y2,r;
  13. signed char dx,dy;
  14. unsigned int color1, color2;
  15.  
  16. alt_up_pixel_buffer_dma_dev* my_pixel_buffer;
  17. // Use the name of your pixel buffer DMA core
  18. my_pixel_buffer = alt_up_pixel_buffer_dma_open_dev(
  19. "/dev/video_pixel_buffer_dma_0");
  20.  
  21. // Check for error and output to the console
  22. if ( my_pixel_buffer == NULL)
  23. printf ("Error: could not open pixel buffer device \n");
  24. else
  25. printf ("Opened pixel buffer device \n");
  26.  
  27. //Очистили основной буфер экрана
  28. alt_up_pixel_buffer_dma_clear_screen(my_pixel_buffer,0);
  29. //Очистили дополнительный буфер экрана
  30. alt_up_pixel_buffer_dma_clear_screen(my_pixel_buffer,1);
  31.  
  32. //Инициализация переменных
  33. color1=0;
  34. color2=0;
  35. x1=200;
  36. y1=150;
  37. r=30;
  38. x2=10;
  39. y2=10;
  40. dx=1;
  41. dy=1;
  42.  
  43. while(1)
  44. {
  45. //Рисуем окружность в дополнительном буфере
  46. vid_draw_circle(my_pixel_buffer, x1, y1, r, color1, 1);
  47.  
  48. //Рисуем прямоугольник для надписи в дополнительном буфере
  49. alt_up_pixel_buffer_dma_draw_box(my_pixel_buffer,x2-1,y2-1,x2+80,y2+10,0x0000,1);
  50. //Выводим надпись visuale.ru
  51. vid_print_string(my_pixel_buffer, x2, y2, color2, cour10_font, "visuale.ru");
  52.  
  53. //Swap buffers and clear---------------------------------------------------------
  54. alt_up_pixel_buffer_dma_swap_buffers(my_pixel_buffer);
  55. while(alt_up_pixel_buffer_dma_check_swap_buffers_status(my_pixel_buffer));
  56.  
  57. //Рисуем окружность в основном буфере
  58. vid_draw_circle(my_pixel_buffer, x1, y1, r, color1, 1);
  59.  
  60. //Рисуем прямоугольник для надписи в основном буфере
  61. alt_up_pixel_buffer_dma_draw_box(my_pixel_buffer,x2-1,y2-1,x2+80,y2+10,0x0000,1);
  62. //Выводим надпись visuale.ru
  63. vid_print_string(my_pixel_buffer, x2, y2, color2, cour10_font, "visuale.ru");
  64.  
  65. //Swap buffers and clear---------------------------------------------------------
  66. alt_up_pixel_buffer_dma_swap_buffers(my_pixel_buffer);
  67. while(alt_up_pixel_buffer_dma_check_swap_buffers_status(my_pixel_buffer));
  68.  
  69. //Вычислили новые координаты и цвета
  70. color1 = rand()%65535;
  71. color2++;
  72. x1 = abs(rand()%400);
  73. y1 = abs(rand()%300);
  74. r = abs(rand()%30);
  75. if(x2>320)dx=-1;
  76. if(x2<2)dx=1;
  77. if(y2>290)dy=-1;
  78. if(y2<2)dy=1;
  79. x2=x2+dx;
  80. y2=y2+dy;
  81. color2++;
  82. }
  83.  
  84. }
  85.  

Ну и по традиции видео работы, и исходники:

Проект: frame_buffer