Jump to content

    
Sign in to follow this  
Konst

Lattice ECP5 и PCIe MSI

Recommended Posts

Всем привет!

Есть задачка - загнать оцифрованный видеопоток на компьютер. В качестве компьютера используется Nvidia Jetson nano,  к нему подключена через PCIe x1 карточка с ПЛИС Lattice ECP5. С платой идет несколько примеров: PCIeBasic, PCIeSGDMA и PCIeThruput. Если я правильно понял, ни в одном из этих примеров MSI не задействован, т.е. во всех случаях инициатором обмена является компьютер. Кто-нибудь использовал прерывания на PCIe IP-ядре от Lattice? Есть у кого-нибудь какая-нибудь дополнительная литература, appnotes, примеры, раскрывающие способы использования IP-ядра? Просто не хотелось бы руками писать свою логику поверх нативного интерфейса IP-ядра и по максимуму использовать инфраструктуру примеров (там используется шина Wishbone, и модули, к которым можно обратиться через маппинг BAR'ов, висят на ней).

 

Share this post


Link to post
Share on other sites

Так, ну кое-что получилось. Оставлю тут на всякий случай, вдруг пригодится кому-нибудь.

Во-первых, при работе с PCI на Jetson Nano выяснилась интересная особенность - по умолчанию Lattice генерирует ядро, в котором Class Code устройства равен 0x000000. Линух на Jetson как-то странно воспринимает этот код и, не смотря на то, что молча выполняет mmap на BAR'ы, читает всегда 0xFF и ничего не записывает, а попытка в драйвере вызвать pci_enable_device заканчивается кодом 22. Если посмотреть таблицу, то код 0x00000 будет соответствовать Unclassified Non-VGA-Compatible device. Если заменить Class Code на 0xFF (Unassigned Class), то драйвер благополучно прописывается в системе.

Во-вторых, на форуме Nvidia нашлась информация (впрочем то сообщение было довольно древним, а сам пока не проверял), что Nvidia Jetson поддерживает только одно прерывание MSI на устройство, а если нужно больше то, пожалуйста, используйте MSI-x.

Теперь по поводу прерываний MSI. 

В одном из примеров (PCIeSGMA) и в ответном для него приложении (написано под винду, исходники поставляются с примером), нашелся тест для прерываний. По нему стало понятно в какие регистры что записывать, чтобы заставить плату поднять линию MSI[0], которая и порождает прерывание. Это прерывание благополучно доставляется до драйвера, о чем сообщает печать в dmesg.

Изначально я наивно полагал, что с помощью MSI мне удастся сразу отправить нужные данные на Jetson, а обработчик будет вызываться тогда, когда данные уютно обустроятся в каком-нибудь буфере, но, похоже, я перепутал мечты с реальностью. В связи с чем новый вопрос - насколько быстро система отвечает на прерывания? Сколько прерываний/с можно отправить на хост? От этого зависит размер буфера, который мне придется держать на ПЛИС.

Share this post


Link to post
Share on other sites

Приветствую!

40 minutes ago, Konst said:

...

Изначально я наивно полагал, что с помощью MSI мне удастся сразу отправить нужные данные на Jetson, а обработчик будет вызываться тогда, когда данные уютно обустроятся в каком-нибудь буфере, но, похоже, я перепутал мечты с реальностью. В связи с чем новый вопрос - насколько быстро система отвечает на прерывания? Сколько прерываний/с можно отправить на хост? От этого зависит размер буфера, который мне придется держать на ПЛИС.

MSI/MSIx прерывания через PCIe это фактически  запись  со стороны  периферийного устройства (FPGA) 32 бит слова по  определенному адресу в PC. Генерировать  такое прерывание можно хоть каждую 1 us, НО сомневаюсь  что ваша OS  потянет обработку прерываний с такой частотой.  Поэтому предельная  частота прерываний определяется  софтом. И в обычных  системах редко бывает выше 1...10KHz. 

Для потока данных прерывание  обычно генерят по окончании пересылки данных посредством контроллера DMA в FPGA.  Поэтому  ван надо внимательней посмотреть на пример  PCIeSGDMA  скорее всего прерывания там генерируются  внутри контроллера DMA.

 

Удачи! Rob.

Share this post


Link to post
Share on other sites
25.12.2020 в 19:02, Konst сказал:

Изначально я наивно полагал, что с помощью MSI мне удастся сразу отправить нужные данные на Jetson, а обработчик будет вызываться тогда, когда данные уютно обустроятся в каком-нибудь буфере, но, похоже, я перепутал мечты с реальностью. В связи с чем новый вопрос - насколько быстро система отвечает на прерывания? Сколько прерываний/с можно отправить на хост? От этого зависит размер буфера, который мне придется держать на ПЛИС.

Не понимаю, какая связь между количеством прерываний и размером буфера? От количества прерываний зависит время, через которое хост узнает о наличии новых данных. Если у вас идет видеопоток, то скорее всего не имеет смысла делать прерывания чаще, чем на видеокадр (т.е. порядка 60 прерываний в секунду в "стандартном" случае).

 

А вот размер буфера в ПЛИС будет зависеть от latency на шине PCI Express - главным образом, от периодически возникающих затыков на шине, приостанавливающих передачу данных. 

Share this post


Link to post
Share on other sites
25.12.2020 в 19:43, RobFPGA сказал:

Для потока данных прерывание  обычно генерят по окончании пересылки данных посредством контроллера DMA в FPGA.  Поэтому  ван надо внимательней посмотреть на пример  PCIeSGDMA  скорее всего прерывания там генерируются  внутри контроллера DMA.

Спасибо за ответ!

К сожалению, в примере c DMA прерывания не используются от слова совсем, хост просто все время читает из PCI. Но к примеру мне точно нужно присмотреться, может мне тоже можно будет сделать совсем без прерываний.

Share this post


Link to post
Share on other sites
5 часов назад, Flood сказал:

Не понимаю, какая связь между количеством прерываний и размером буфера? От количества прерываний зависит время, через которое хост узнает о наличии новых данных. Если у вас идет видеопоток, то скорее всего не имеет смысла делать прерывания чаще, чем на видеокадр (т.е. порядка 60 прерываний в секунду в "стандартном" случае).

 

А вот размер буфера в ПЛИС будет зависеть от latency на шине PCI Express - главным образом, от периодически возникающих затыков на шине, приостанавливающих передачу данных. 

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

А видеопоток не сильно мощный - 16 бит яркостного сигнала (целимся в формат пикселя, который в V4L2 в Linux называеся Y16) с разрешением 800х600 или 1600х1200 при 25 к/с. Родной памяти плиска имеет 108 блоков по 1024 18-разрядных слова, т.е. всего  1 990 656 бит.

Share this post


Link to post
Share on other sites

Приветствую!

17 minutes ago, Konst said:

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

А видеопоток не сильно мощный - 16 бит яркостного сигнала (целимся в формат пикселя, который в V4L2 в Linux называеся Y16) с разрешением 800х600 или 1600х1200 при 25 к/с. Родной памяти плиска имеет 108 блоков по 1024 18-разрядных слова, т.е. всего  1 990 656 бит.

Ну вот берите и считайте  - 16 бит  800х600х25  получается ~24 MB/s. Для  1600x1200 все в 4 раза хуже - ~96 MB/s.  Программным  чтением через CPU вы такой поток не вытащите, даже с большими буферами и частыми прерываниями.  Так что без DMA вам никак. 

А  когда DMA есть то буфера в FPGA нужны (как и говорили выше) небольшие - лишь для сглаживания пиковых провалов на шине PCIe и задержек при пере-инициализации DMA. Ну и прерывания если и нужны  будут то только для этого, что как раз можно совместить с размером кадра. 

 

Удачи! Rob.

Share this post


Link to post
Share on other sites
17 часов назад, Konst сказал:

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

Причем тут вообще DDR3 на отладочной плате? Возможно, вы не до конца продумали и представляете себе путь движения данных. Нарисуйте потоки, их инициаторы и приемники на схеме - возможно, тогда станет понятнее.

 

Обыкновенно, задачи типа вашей решаются следующим образом:

В системе есть периферийное устройство (плата с ПЛИС с интерфейсом видеокамеры или видеовхода и ограниченным размером буферной памяти) и хост-система (материнская плата с центральным процессором и кучей памяти). Тогда:

- хост-система выделяет в своей безбрежной памяти набор приемных буферов (не менее двух, лучше трех), размером на видеокадр каждый и настраивает периферийное устройство на прием в эти буфера;

- периферийное устройство (ПЛИС) работает в режим bus-master и инициирует передачу данных в память хост-процессора по переданным ему адресам приемного буфера (этот процесс называется DMA);

- по окончании заполнения очередного буфера устройство возбуждает прерывание и переходит к приему новых данных в следующий буфер;

- центральный процессор по этому прерыванию понимает, что буфер готов, забирает его и дает периферийному устройству следующий буфер.

Прерывания нужны, чтобы быстро узнать о готовности буфера, не отвлекаясь на поллинг. Это не обязательно, но довольно удобно при низком темпе поступления данных (а 60 кадров в секунду - это медленно). Существуют более эффективные способы приема данных, чем подтверждения по прерываниям, но для приема видеоданных с частотой 60 Гц они не обязательны.

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

 

Share this post


Link to post
Share on other sites
2 часа назад, Flood сказал:

Возможно, вы не до конца продумали и представляете себе путь движения данных. Нарисуйте потоки, их инициаторы и приемники на схеме - возможно, тогда станет понятнее.

Не возможно, а совершенно точно:biggrin:. Работу с PCI я не так представлял, но по Вашему возмущению относительно размера буфера из первого поста понял, что где-то не прав:biggrin:

Share this post


Link to post
Share on other sites
16 минут назад, toshas сказал:

Как вы решаете или планируете решить вопрос cache coherency на Jetson NANO ?

Пока что я читаю 15 главу книжки Linux Device Drivers, параллельно пытаясь понять, что от меня потребуется со стороны платы на Lattice. 

Но из того, что я прочитал, мне показалось, что эта проблема должна возникать, когда устройство и драйвер расшаривают одну область памяти на двоих и используют ее вместе, т.е. и процессор и драйвер пишут в одну и ту же область. Я же собираюсь, как и советовал Flood, выделить несколько буферов под DMA и циклически менять их местами, т.е. каждрый раз перезаряжать PCI-плату, подсовывая ей новый адрес приемного буфера. А проц будет только читать. В таком случае тоже может возникнуть проблема когеренции? Если так, то должны же быть какие-нибудь механизмы, позволяющие решить этот вопрос, кроме как запросить у ос специальный буфер через dma_alloc_coherent?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this