Для проверки основных систем нашей платы VE-10CL025 таких как FPGA, HDMI, SDRAM было решено создать проект, на основе процессорного ядра NIOS II. В нашем проекте процессор NIOS с помощью упрощенной библиотеки simple_graphics формирует изображение в экранном буфере, расположенном в SDRAM памяти. Далее данные из SDRAM считываются при помощи DMA, после чего передаются на блок генерации HDMI сигналов. Все компоненты системы, кроме блока генерации HDMI — стандартные (встроены в Quartus).Теперь подробнее о том, как это реализовать. Для начала нужно создать пустой проект в Quartus, сконфигурировать его под конкретную ПЛИС и создать систему SOPC. Более подробно это описано в нашей статье Процессор Nios II для VE-EP4CE10E.
Схема получившейся SOPC:
Рассмотрим компоненты, составляющие нашу SOPC:
Компонент clk_0 (Clock Source) Входной буфер для сигнала частоты и сброса.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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:
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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:
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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:
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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, остальные настройки описаны в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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). Полезен для отладки.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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 системы. В настройках желательно ввести свое значение (произвольное).
Страница | Параметр | Значение | Единицы |
---|---|---|---|
altera_avalon_sysid_qsys | 32 bit System ID | 0x12345678 |
Компонент onchip_memory2_0 (On-Chip Memory (RAAM or ROM)) Память программ встроенная в FPGA. Это ОЗУ процессора. Также здесь хранится сама программа процессора. В настройках памяти нужно установить размер ОЗУ — 32000 байт.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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 будет размещаться видеобуфер. Настройки контроллера приведены в таблице.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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, или прямого доступа к памяти, т.е. без участия основного процессора.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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 пикселя.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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. Кроме того, он задерживает данные на время передачи синхроимпульсов.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
Pixel Format | Color Bits | 8 | |
Pixel Format | Color Planes | 1 |
Компонент video_sync_generator_0 (Video Sync Generator Intel FPGA IP) Компонент, формирующий видеосигнал для HDMI. В частности, он формирует сигналы горизонтальной и вертикальной синхронизации, и управляет идущим на него потоком данных, приостанавливая его во время передачи синхроимпульсов.
Страница | Параметр | Значение | Единицы |
---|---|---|---|
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 сигнала совпадали.
Схема получившейся системы:
Для формирования изображения используется модифицированная библиотека simple_graphics. В программе формируется три вида объектов: цветные круги, прямоугольная область для надписи и текстовая надпись. Изображение сначала формируется в дополнительном буфере, затем буфера переключаются, и точно такое-же изображение формируется в основном буфере.
Исходный код программы:
C++ Code:
#include "main.h" #include "simple_gfx/simple_graphics.h" #include <stdio.h> #include <stdlib.h> #include <math.h> #include "system.h" #include "sys/alt_log_printf.h" #include "altera_up_avalon_video_pixel_buffer_dma.h" int main(void) { unsigned int x1,y1,x2,y2,r; signed char dx,dy; unsigned int color1, color2; alt_up_pixel_buffer_dma_dev* my_pixel_buffer; // Use the name of your pixel buffer DMA core my_pixel_buffer = alt_up_pixel_buffer_dma_open_dev( "/dev/video_pixel_buffer_dma_0"); // Check for error and output to the console if ( my_pixel_buffer == NULL) printf ("Error: could not open pixel buffer device \n"); else printf ("Opened pixel buffer device \n"); //Очистили основной буфер экрана alt_up_pixel_buffer_dma_clear_screen(my_pixel_buffer,0); //Очистили дополнительный буфер экрана alt_up_pixel_buffer_dma_clear_screen(my_pixel_buffer,1); //Инициализация переменных color1=0; color2=0; x1=200; y1=150; r=30; x2=10; y2=10; dx=1; dy=1; while(1) { //Рисуем окружность в дополнительном буфере vid_draw_circle(my_pixel_buffer, x1, y1, r, color1, 1); //Рисуем прямоугольник для надписи в дополнительном буфере alt_up_pixel_buffer_dma_draw_box(my_pixel_buffer,x2-1,y2-1,x2+80,y2+10,0x0000,1); //Выводим надпись visuale.ru vid_print_string(my_pixel_buffer, x2, y2, color2, cour10_font, "visuale.ru"); //Swap buffers and clear--------------------------------------------------------- alt_up_pixel_buffer_dma_swap_buffers(my_pixel_buffer); while(alt_up_pixel_buffer_dma_check_swap_buffers_status(my_pixel_buffer)); //Рисуем окружность в основном буфере vid_draw_circle(my_pixel_buffer, x1, y1, r, color1, 1); //Рисуем прямоугольник для надписи в основном буфере alt_up_pixel_buffer_dma_draw_box(my_pixel_buffer,x2-1,y2-1,x2+80,y2+10,0x0000,1); //Выводим надпись visuale.ru vid_print_string(my_pixel_buffer, x2, y2, color2, cour10_font, "visuale.ru"); //Swap buffers and clear--------------------------------------------------------- alt_up_pixel_buffer_dma_swap_buffers(my_pixel_buffer); while(alt_up_pixel_buffer_dma_check_swap_buffers_status(my_pixel_buffer)); //Вычислили новые координаты и цвета color1 = rand()%65535; color2++; x1 = abs(rand()%400); y1 = abs(rand()%300); r = abs(rand()%30); if(x2>320)dx=-1; if(x2<2)dx=1; if(y2>290)dy=-1; if(y2<2)dy=1; x2=x2+dx; y2=y2+dy; color2++; } }
Ну и по традиции видео работы, и исходники:
Проект: frame_buffer