|
АЦП+FPGA+NIOS |
|
|
|
Oct 17 2013, 08:15
|
Частый гость
Группа: Свой
Сообщений: 76
Регистрация: 12-02-10
Из: Хабаровск
Пользователь №: 55 441
|
Цитата(lekintr @ Oct 17 2013, 10:12) Напишите отдельный модуль, который забирает данные с АЦП, обрабатывает их и кладет в свою память. На выходе поставьте FIFO, которое подключено к шине NIOS. Размер FIFO позволит отработать любые разумные задержки, главное чтобы в среднем время чтения из FIFO было меньше времени его заполнения. Задачка несложная.. Правильно ли я вас понял? Мне надо написать например на VHDL модуль памяти длиной n 14-битных слов в который будут записываться данные с АЦП. Этот модуль будет промежуточным буфером. Поскольку длина n намного меньше 500000, то модуль будет использовать только внутреннюю память ПЛИС. Вместе с тем, модуль должен быть подключен к софт-процессору с FIFO интерфейсом на борту. В программе софт процессора посредством функций вроде altera_avalon_fifo_read_fifo я смогу быстро читать содержимое буфера и обработав его, писать в SDRAM, подключенную к процессор?
|
|
|
|
|
Oct 20 2013, 09:52
|
Группа: Новичок
Сообщений: 5
Регистрация: 20-10-13
Пользователь №: 78 808
|
Если я правильно понял задачу, то исходные данные выглядят так - из сигнала последовательно берутся выборки по 500 000 слов между которыми происходит усреднение. X - вход 500 000 слов Y - выход 500 000 слов Y(n) = А*X + (1 - А)*Y(n - 1) Понятно, что у Cyclone III не хватит внутренней памяти и надо использовать внешнюю. Почти со 100% уверенностью заявляю, что NIOS не справится с обработкой сигнала с дискретизацией 5МГц. Надо делать хардовую обработку. В приложении мои мысли на этот счет. На словах: нужны два компонента (чтения/записи) для доступа к SDRAM через Avalon MM (доступ следует делать с brust), работающих на частоте шины (зеленая рамка), две FIFO которые развяжут clock АЦП и clock шины, и будут служить буфером для доступа к SDRAM, ну и собственно усредняющий блок, который берет значение с АЦП с FIFO умножает/складыет и кладет в другое FIFO. Все пишется ручками и вставляется в SoPC, для FIFO берется MegaFunction.
|
|
|
|
|
Oct 20 2013, 11:27
|
Гуру
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454
|
Цитата(Andrey S @ Oct 20 2013, 13:52) X - вход 500 000 слов Y - выход 500 000 слов Y(n) = А*X + (1 - А)*Y(n - 1)
Я вижу что в один момент используется прошлое измерение и текущее. Другими словами не надо хранить 500 000 входных и выходных слов. надо на лету читать и класть в память. 5 МГц на 100 МГц это 20 тактов, с 1 тактовыми умножителями (пусть с конвеером 3 тактовые) вполне можно уложится. ДСП модули есть в ПЛИС?
|
|
|
|
|
Oct 20 2013, 13:09
|
Группа: Новичок
Сообщений: 5
Регистрация: 20-10-13
Пользователь №: 78 808
|
Цитата(Golikov A. @ Oct 20 2013, 15:27) Я вижу что в один момент используется прошлое измерение и текущее. Другими словами не надо хранить 500 000 входных и выходных слов. надо на лету читать и класть в память. 5 МГц на 100 МГц это 20 тактов, с 1 тактовыми умножителями (пусть с конвеером 3 тактовые) вполне можно уложится. ДСП модули есть в ПЛИС? Надо хранить 500 000 выходных слов, X и Y - вектор. Усреднение не между отсчетами, а между векторами, в Y(n) = a*X + (1 - a)*Y(n - 1) n - индекс вектора(а не отсчета). А насчет производительности NIOS, нужно пробовать...
|
|
|
|
|
Oct 22 2013, 12:07
|
Частый гость
Группа: Свой
Сообщений: 76
Регистрация: 12-02-10
Из: Хабаровск
Пользователь №: 55 441
|
Цитата(Andrey S @ Oct 20 2013, 12:52) нужны два компонента (чтения/записи) для доступа к SDRAM через Avalon MM (доступ следует делать с brust), работающих на частоте шины (зеленая рамка), две FIFO которые развяжут clock АЦП и clock шины, и будут служить буфером для доступа к SDRAM, ну и собственно усредняющий блок, который берет значение с АЦП с FIFO умножает/складыет и кладет в другое FIFO. Все пишется ручками и вставляется в SoPC, для FIFO берется MegaFunction. Вы правильно поняли задачу, усреднение производится именно между векторами, а не отсчетами. По поводу вашего совета пока обдумываю, возможно не достаточно знаком с шиной Avalon. Буду читать. Мне схема работы видится как на приложенной картинке. Если кратко: АЦП пишет данные поочередно в буферы. Выбор буфера осуществляют сигналы заполненности. Буфер представляет собой сдвиговый регистр длиной n слов (на картинке n=1024). После заполнения одного буфера АЦП переключается на другой, а в процессор подается сигнал о готовности порции данных. За время заполнения второго буфера проводится быстрая передача данных в процессор где все аккуратно складывается с усреднением в SDRAM. Есть ли компонент для быстрой передачи порции данных длиной n слов в процессор? Могу ли я так рассчитать размер буфера, что времени его заполнения хватит на обработку в софте?
|
|
|
|
|
Oct 22 2013, 18:06
|
Группа: Новичок
Сообщений: 5
Регистрация: 20-10-13
Пользователь №: 78 808
|
Цитата(Dootch @ Oct 22 2013, 16:07) Есть ли компонент для быстрой передачи порции данных длиной n слов в процессор? Не понимаю, что значит передать порцию данных длиной n слов в процессор... Процессор берет данные из памяти загружает в регистры, выполняет операцию, записывает результат в память. Вместо памяти он может читать из FIFO, к которой вы сделаете avalon slave интерфейс (без brust, это проще чем мастер, если решитесь - я подскажу).
Можно обойтись одним FIFO, скажем 2048 слов, начинаете читать из него когда в нем больше половины заполнено в этом случаи вы гарантировано можете последовательно прочитать 1024 слова не тратя время на опрос на наличие слова в очереди при каждом чтении. Т.е. описываете устройство с avalon slave интерфейсом для доступа к регистрам, у которого внутри FIFO куда пишутся данные с АЦП. Мин. набор регистров: control - здесь либо ресет, либо разрешение на захвата данный с АЦП, чтобы иметь возможность управлять стартом status - флаг - число слов в очереди больше половины, флаг - очередь заполнена (в этом случаи пиши пропал, проц. не успевает) read_data - отсюда читается слово из очереди. В nios примерно след: CODE while (1) { if ( iord(reg_status) & FIFO_FULL ) { Panik!!! }
if ( iord(reg_status) & FIFO_HALF_FULL ) { for ( int i = 0; i < 1024; i++ ) { int x = iord(reg_read_data); int y = ...
y = ( a * x + b * y ) >> ...; y в память... } } }
Если АЦП знаковое расширение знака лучше сделать в хардваре при чтении из FIFO, что бы проц. сэкономить. Как писалось выше при 100МГц у вас есть 20 тактов на отсчет, что очень немного. Само собой в цикле никаких вызовов функций, принтфов, арифметика целочисленная, полная оптимизация, на SDRAM включенный кэш. Если процессор справится, то никакие другие задачи он уже не потянет. Какова последующая обработка, после фильтрации?... Цитата(Dootch @ Oct 22 2013, 16:07) Могу ли я так рассчитать размер буфера, что времени его заполнения хватит на обработку в софте? С включенным кэшем при чтении из SDRAM задержка будет только при чтении первого слова, последующие будут в кэше и так каждые 500000. Т.е. длина очереди должна скомпенсировать это время, я думаю что 1024 хватит за глаза.
|
|
|
|
|
Oct 29 2013, 07:36
|
Частый гость
Группа: Свой
Сообщений: 76
Регистрация: 12-02-10
Из: Хабаровск
Пользователь №: 55 441
|
Пошерстил литературу, кажется начинаю разбираться понемногу. Поправьте если ошибаюсь. Собрал ФИФО в MegaWizard-e. Основные параметры: 2048 слов длиной 14 бит (УГО прикреплено). Соответственно у меня создался vhd файл с описанием моего ФИФО. Далее по методу, описанному в ftp://ftp.altera.com/up/pub/Altera_Materi..._components.pdf я прикручиваю к моему ФИФО интерфейс Avalon-ST и создаю на основе своих vhd файлов компонент в SOPC builder или Qsys. Цепляю полученный компонент к соф-процессору, после чего начинается программный прием и обработка как указал Andrey S.
Эскизы прикрепленных изображений
|
|
|
|
|
Oct 29 2013, 18:38
|
Группа: Новичок
Сообщений: 5
Регистрация: 20-10-13
Пользователь №: 78 808
|
Avalon-ST - это Avalon Streaming Interfaces, нужен Avalon-MM (Memory-Mapped), в помощь Avalon Interface Specifications . Компонент для SOPC builder или Qsys описывается в *_hw.tcl, рекомендую отказаться от мастера и почитать описание для Qsys. Как подсказку, даю пример от которого можно отталкиваться (извиняюсь писал без проверки), к компоненту подсоединяется NIOS, внутри 4 регистра: 0 - status (очередь пуста, заполнена, заполнена на половину), при чтении из 1-го происходит чтение из очереди, 2 - тестовый регистр из него всегда читается 0xAAAAAAAA, 3 - тестовый регистр в него можно писать и читать. test_component будет виден в Qsys с версии 12.0 test_component_hw.tcl CODE package require -exact qsys 12.0
#------------------------------------------------------------------------------ # module #------------------------------------------------------------------------------ set_module_property NAME test_component set_module_property VERSION 1.0 set_module_property AUTHOR "Andrey S" set_module_property EDITABLE false set_module_property HIDE_FROM_SOPC true
#------------------------------------------------------------------------------ # file sets #------------------------------------------------------------------------------ add_fileset QUARTUS_SYNTH QUARTUS_SYNTH "" "" set_fileset_property QUARTUS_SYNTH TOP_LEVEL test_component_top
add_fileset_file "test_component.vhd" VHDL PATH "test_component.vhd"
#--------------------------------------------------------------------- # Clock & Reset connection points #--------------------------------------------------------------------- add_interface "clk" clock end add_interface "reset" reset end # <interface> <property> <value> set_interface_property "reset" associatedClock "clk" set_interface_property "reset" synchronousEdges DEASSERT # <interface> <port> <type> <dir> <width> add_interface_port "clk" clk clk Input 1 add_interface_port "reset" reset reset Input 1
#--------------------------------------------------------------------- # AVALON #--------------------------------------------------------------------- add_interface "csr" avalon slave # <interface> <property> <value> set_interface_property "csr" associatedClock "clk" set_interface_property "csr" associatedReset "reset" # <interface> <port> <type> <dir> <width> add_interface_port "csr" bus_address address Input 2 add_interface_port "csr" bus_waitrequest waitrequest Output 1 add_interface_port "csr" bus_readdata readdata Output 32 add_interface_port "csr" bus_read read Input 1 add_interface_port "csr" bus_writedata writedata Input 32 add_interface_port "csr" bus_write write Input 1
test_component.vhd CODE library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity test_component_top is port ( clk : in std_logic; reset : in std_logic; bus_address : in std_logic_vector(1 downto 0); bus_read : in std_logic; bus_readdata : out std_logic_vector(31 downto 0); bus_waitrequest : out std_logic; bus_write : in std_logic; bus_writedata : in std_logic_vector(31 downto 0) ); end entity test_component_top;
architecture rtl of test_component_top is signal rdreq : std_logic; signal wrreq : std_logic; signal rdresp : std_logic; signal wrresp : std_logic; -- REGS constant C_REG_STATUS : natural := 0; constant C_REG_RDDATA : natural := 1; constant C_REG_TEST_AA : natural := 2; constant C_REG_TEST : natural := 3;
signal reg_test : std_logic_vector(31 downto 0);
-- FIFO (need show-ahead) signal fifo_q : std_logic_vector(13 downto 0); signal fifo_rdusedw : std_logic_vector(10 downto 0); signal fifo_rdfull : std_logic; signal fifo_rdempty : std_logic; signal fifo_rdreq : std_logic; begin process( clk, reset ) begin if ( reset = '1' ) then rdreq <= '0'; wrreq <= '0'; state <= ST_WAIT_REQUEST; elsif rising_edge(clk) then -- Default rdreq <= '0'; wrreq <= '0'; -- State case state is when ST_WAIT_REQUEST => if ( bus_read = '1' ) then rdreq <= '1'; state <= ST_WAIT_RESPONSE; elsif ( bus_write = '1' ) then wrreq <= '1'; state <= ST_WAIT_RESPONSE; end if; when ST_WAIT_RESPONSE => if ( rdresp = '1' or wrresp = '1' ) then state <= ST_WAIT_REQUEST; end if;
when others => state <= ST_WAIT_REQUEST; end case; end if; end process; bus_waitrequest <= ( bus_read or bus_write ) when ( state = ST_WAIT_REQUEST ) else not( rdresp or wrresp );
-- Write wrresp <= wrreq; process( clk, reset ) begin if ( reset = '1' ) then reg_test <= ( others => '0' ); elsif rising_edge(clk) then if ( wrreq = '1' ) then if ( unsigned(bus_address) = C_REG_STATUS ) then -- Read only elsif ( unsigned(bus_address) = C_REG_RDDATA ) then -- Read only elsif ( unsigned(bus_address) = C_REG_TEST_AA ) then -- Read only elsif ( unsigned(bus_address) = C_REG_TEST ) then reg_test <= bus_writedata; end if; end if; end if; end process; -- Read process( clk, reset ) begin if ( reset = '1' ) then rdresp <= '0'; bus_readdata <= ( others => '0' ); elsif rising_edge(clk) then rdresp <= rdreq; bus_readdata <= ( others => '0' ); if ( unsigned(bus_address) = C_REG_STATUS ) then bus_readdata(0) <= fifo_rdempty bus_readdata(1) <= fifo_rdfull; bus_readdata(2) <= fifo_rdusedw(fifo_rdusedw'length - 1); elsif ( unsigned(bus_address) = C_REG_RDDATA ) then bus_readdata(fifo_q'range) <= fifo_q; elsif ( unsigned(bus_address) = C_REG_TEST_AA ) then bus_readdata <= x"AAAA_AAAA"; elsif ( unsigned(bus_address) = C_REG_TEST) ) then bus_readdata <= reg_test; end if; end if; end process; fifo_rdreq <= rdreq when ( unsigned(bus_address) = C_REG_RDDATA ) else '0';
end architecture rtl;
успехов...
Сообщение отредактировал Andrey S - Oct 29 2013, 18:40
|
|
|
|
|
Oct 30 2013, 10:06
|
Частый гость
Группа: Свой
Сообщений: 76
Регистрация: 12-02-10
Из: Хабаровск
Пользователь №: 55 441
|
Andrey S, большое спасибо за полезную литературу и примеры. Для проверки быстродействия по примеру, описанному в ftp://ftp.altera.com/up/pub/Altera_Materi..._components.pdf я собрал регистр для чтения и записи с Avalon-MM интерфейсом. В Eclipse запущен простой код CODE int z; while(1) { IOWR(0x11048,0,z); z++; }
где по кругу в регистр выводится значение переменной z. Младший разряд регистра выведен на ногу ПЛИС для мониторинга осциллографом. При частоте NIOS 100 МГц максимальная частота переключения регистра составляет 1,7 МГц при использовании оптимизации Level 3. Такой частоты явно недостаточно. По моим скромным подсчетам необходима скорость около 7 МГц. На плате стоит ПЛИС Altera EP3C16F484C6, Speed Grade 6. Пробовал увеличивать частоту работы процессора до 150 и 200 МГц, процессор генерируется, компиляция в Quartus проходит успешно, но запустить код в Eclipse не выходит. Возможно я что-то делаю не так. Есть ли способ повышения скорости работы процессора? Возможно есть смысл писать код на ассемблере?
|
|
|
|
|
Oct 30 2013, 11:34
|
Частый гость
Группа: Свой
Сообщений: 76
Регистрация: 12-02-10
Из: Хабаровск
Пользователь №: 55 441
|
Цитата(DASM @ Oct 30 2013, 14:10) Зачем вам программно дергать регистр ? Делайте аппаратно, своим верилог модулем, для чего это ? Повышать не стоит тактовую, нестабилен этот НИОС на таких частотах. На асме писать - тем более. Может Циклон 5 / Zynq 7010/20 поглядеть ? В данном случае я проверяю быстродействие чтения процессором данных из будущего FIFO модуля, то есть вместо IOWR(0x11048,0,z) будет чтение данных и их обработка. Скорость выборки из FIFO должна быть выше скорости записи туда. Начинаю задумываться о написании аппаратного модуля сбора и обработки данных с последующей записью в SDRAM минуя процессор. Пока трудно оценить трудоемкость такой работы. С SDRAM не дружил пока что.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|