Jump to content

    

Cyclone3, DDR2 и АЦП

Здравствуйте,

возникла у меня довольно странная проблема.

Есть плата собственного производства, на ней установлены Cyclone3, память DDR2 и АЦП. Задача - по нажатию кнопки в программе на компьютере сохранить данные от АЦП в памяти и затем передать их в компьютер. Это реализовано с использованием прямого доступа к памяти и FIFO. Работает хорошо, но сделано это было в Quartus 9.0 и Nios IDE, т.е. без eclipse.

Сейчас использую Quartus 12.1sp1. Открываю старый проект перегенерю систему в SOPC Builder, компелирую в Quartus, компелирую программу в Eclipse, прошиваю - не работает. А точнее всё запускается, програма переходит в нужную подпрограмму и зависает в ожидании окончания DMA.

Причём проделал такой эксперимент взял старый старые и новые .sof и .elf и попытался перекомбинировать старое с новым, чтобы понять где ошибка (т.к. базовые адреса в SOPC не менялись я подумал, что так можно делать). Результат - хорошо работает только старые .sof и .elf любые другие комбинации работаю плохо и либо зависают при первом же нажатии на кнопку получения данных или через короткое время.

 

В чём может быть проблемма? Может какие нибудь особенности нового Quartus или Eclipse и они как-то по другому компилируют?

 

P.S. Т.е. получается, что на старой прошивке ПЛИС новая программа работает плохо. Т.е. дело в компиляторе программы. Хотя это тоже очень странно ведь программа только инициализирует DMA и запускает приём данных, а далее данные записываются в память минуя процессор. Так почему же он зависает ведь прошивка старая - работающая?

Edited by djhall

Share this post


Link to post
Share on other sites

Есть подозрение что в 12.1 по сравнению с 9 изменился блок DMA. Как правило, вместе с изменениями в железе (sof) делается изменение в BSP в драйвере. В таком случае комбинации нового elf и старого sof работать правильно просто не могут. Ну а что там изменилось...

Не помню точно с этим ли, давно это было, но у меня например была проблема с ready latency. Пришлось подрихтовать подключение к интерфейсу Avalon-ST в своем блоке.

Share this post


Link to post
Share on other sites

Да, видимо это возможно, но при сборке системы с нуля для 12.1sp1 всё работает ещё хуже. Может быть действительно изменильсь сами компоненты dma, контроллер ddr памяти и clock crossing и теперь такая конфигурация не работает или работает не так как я ожидаю. Видимо придётся делать пробные прошивки и тестировать пропускную способность всей системы.

Вообще-то я использую Memory-Mapped интерфейс для получения данных от быстродействующего АЦП. Данные записываются в FIFO и затем DMA считывает их оттуда и распределяет в памяти. Причём DMA и память работают на разных частотах и между ними стоит clock crossing. Может какое-то конкурирующее устройство на шине мешает передачи и FIFO переполняется. Может так делать неправильно и нужно использовать Streaming? Для этого нужно использовать SG-DMA, а я его как-то не очень люблю из-за того, что он не может передать 65536 байт за раз. Да и поможет ли это?

Share this post


Link to post
Share on other sites
Да, видимо это возможно, но при сборке системы с нуля для 12.1sp1 всё работает ещё хуже. Может быть действительно изменильсь сами компоненты dma, контроллер ddr памяти и clock crossing ...

Была похожая проблема после переноса проекта с Q9.1 на Q11 перестал работать контроллер DDR SDRAM. Пляски с бубнами не помогли. Когда надоело шаманить вернулся на Q9.1.

 

Вообще-то я использую Memory-Mapped интерфейс для получения данных от быстродействующего АЦП. Данные записываются в FIFO и затем DMA считывает их оттуда и распределяет в памяти. Причём DMA и память работают на разных частотах и между ними стоит clock crossing.

Странное решение. А процессор и остальная перефирия на каком клоке сидит?

Обычно, если АЦП работает на частоте отличной от системы, синхронизация делается через FIFO. При этом не теряется быстродействие всей системы.

На вход FIFO обычно проще подключать Streaming, но можно и ММ.

SG-DMA при правильном использовании однозначно быстрее, только нужно ли Вам это?

Share this post


Link to post
Share on other sites
Странное решение. А процессор и остальная перефирия на каком клоке сидит

Процессор, DMA и мой компонент для получения данных от АЦП (вместе с FIFO) работают от одной частоты в 100МГц, DDR2(MT47H64M16HR) работает от 133.333МГц в режиме Half-rate, т.е. локальная шина имет размер 64бита и частоту 66,7МГц. Clock-crossing передаёт данные между 100 и 66,7Мгц. Возможно это и не лучшая конфигурация и если кто-то сможет предложить лучше с удовольствием попробую.

 

А пока решил поэкспериментировать. Запустил DDR2 от 200МГц в режиме Half-rate, т.е. теперь локальная шина имет размер 64бита и частоту 100МГц и от неё тактируются все остальные компоненты. Clock-crossing выбросил. С помощью SignalTap выяснил, что зависание происходит из-за переполнения FIFO, причём переполнение происходит не сразу, а постепенно и видимо в моменты когда доступ к памяти перехватывает конкурирующее устройство(видимо процессор). Ну то есть скорости хватает впритык и малейшая пауза в чтении данных из FIFO в конечном счёте приводит переполнению. В SignalTap также видно, что чтение из моего компонента с FIFO с помощью DMA происходит прерывисто - один такт чтение далее один такт простой и следующий такт опять чтение.

В чём может быть причина такого чтения ведь мой компонент поддерживает чтение по каждому такту?

 

 

Share this post


Link to post
Share on other sites

1) арбитраж доступа к DDR памяти. Попробуйте проставьте вручную своему компоненту максимальный приоритет

2) для чтения/записи каждый такт ваш компонент должен уметь burst

Share this post


Link to post
Share on other sites
1) арбитраж доступа к DDR памяти. Попробуйте проставьте вручную своему компоненту максимальный приоритет

Аритраж уже выставлен в пользу моего компонента. И в принципе изменяя приоритеты для разных мастеров на шине можно добиться нормальной работы. Но как-то это не надёжно я попробовал на разных компьютерах одни и теже настройки для системы и после компиляции одна прошивка заработала, а другая нет (хотя может я какие-то настроики в Quartus не учёл).

 

2) для чтения/записи каждый такт ваш компонент должен уметь burst

На счёт burst, то это потребует довольно серьёзной переделки компонента, чего не хотелось бы.

Может быть попробовать увеличить размерность шины до 64 бит?

 

Правильно ли я понимаю арбитраж? Например, если мастер1 читает данные из слэйва и в это время мастер2 тоже хочет получить доступ к этому же слэйву, то он его обязательно получит и отношение времён доступа к слэйву для мастера1 и мастера2 будет равно соотношению чисел арбитража выставленных в SOPC builder для этих мастеров.

Share this post


Link to post
Share on other sites
моего компонента с FIFO с помощью DMA происходит прерывисто - один такт чтение далее один такт простой и следующий такт опять чтение.

В чём может быть причина такого чтения ведь мой компонент поддерживает чтение по каждому такту?

 

Этот DMA компонент так и работает - читает во внутренний буфер 1 такт, потом записывает -2 такт. У DMA read и write на разных шинах?

Если мне не изменяет склероз, обычный DMA с burst не работает.

Сложно советовать нe имея перед глазами всей структуры проекта, но варианты такие:

1.SG-DMA

2. перенос DMA и FIFO в клоковый домен памяти.

А лучше и то и другое и увеличить кеш процессора и длину FIFO.

Share this post


Link to post
Share on other sites
Этот DMA компонент так и работает - читает во внутренний буфер 1 такт, потом записывает -2 такт.

Давным давно отлаживал систему с DMA и лично видел, что запись была по каждому фронту. Правда это было очень давно.

В DMA есть FIFO поэтому она должна (а точнее я хочу, чтобы DMA так делала) читать несколько циклов и потом записывать несколько циклов. Конечно если чтение и запись идут в одну и туже память то без разделения по времени ни чего не получится, а вот если чтение идёт из переферийного устройства, а запись в память, то казалось бы нет необходимости разделения по времени и запись может идти по каждому такту. Надо поэкспериментировать, но у меня остаётся надежда заставить DMA работать по каждому такту.

 

У DMA read и write на разных шинах?

Не совсем понял вопрос. DMA read и DMA write это отдельные мастеры и соответственно разные шины. Они оба подключены к контроллеру DDR памяти и некоторым другим компонентам в системе, а к моему компоненту получения данных от АЦП подключен только DMA read.

 

1.SG-DMA

Всегда недолюбливал SG DMA. Надо наверное с ним хорошенько разобраться.

SG DMA содержит четыре мастера, т.е. два дополнительных мастера для дискрипторов. Если всё это подключить к контроллеру DDR памяти то минимум к нему будет подключено шесть мастеров и плюс мои собственные. Мне почему-то кажется что это очень плохо для производительности и для разводки по кристалу. Видимо шины для дискрипторов лучше подключать к внутренней памяти ПЛИС.

Но как же мне передать большой объём данных ведь в дискрипторе поле для длинны передачи всего 16 бит, т.е. 65536 байт? Увеличивать количество дескрипторов? Так до какой степени, в ПЛИС же память не слишком большая?

 

2. перенос DMA и FIFO в клоковый домен памяти.

Уже сделано.

 

Share this post


Link to post
Share on other sites

если говорить про SGDMA то суть в следующем:

под дескрипторы берется onchip_ram

прикидываете сколько дескрипторов поместиться в вашей onchip_ram

делаете uncached_malloc() столько раз, сколько у вас есть дескрипторов

Составляете связанный список из дескрипторов, собираете дескрипторы в цепочку alt_avalon_sgdma_construct_stream_to_mem_desc()

запускаете SGDMA.

 

при этом начинает заполнятся первый кусок памяти, выделенный через uncached_malloc(). сразу после - второй, и т.д. DMA-операция продолжается до тех пор, пока всё выделенное пространство не быдет записано. После записи каждого куска выделенной памяти можно настроить выдачу прерывания. После этого нужно "перезарядить" DMA при помощи alt_avalon_sgdma_construct_stream_to_mem_desc(), и снова стартануть.

 

Другой вариант, - при формировании цепочки дескрипторов их можно "закольцевать", и запустить DMA, при этом DMA-запись не будет останавливаться вообще никогда. Тут важно успевать что-то делать с данными пока они не будут перезаписаны следующкей порцией приходящих данных.

 

 

зы. за одну операцию запуска можно передать гораздо больше чем 64k

Share this post


Link to post
Share on other sites
... Видимо шины для дискрипторов лучше подключать к внутренней памяти ПЛИС...

Лучше разработать IP контроллера дескрипторов для SG-DMA и подключить шины для дескрипторов к нему. Nios II процессор будет однократно программировать контроллер дескрипторов и далее SG-DMA будет выполнять самостоятельно все пересылки данных. К контроллеру дескрипторов можно подключить внешние сигналы, управляющие очередностью (приоритетом) пересылок данных...

 

Подумайте в этом направлении ;) Ощутите, какие открываются перспективы B)

Share this post


Link to post
Share on other sites
Лучше разработать IP контроллера дескрипторов для SG-DMA

 

Гениально!!!

Так и сделаю. Спасибо. Жаль не я это придумал.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this