Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Интерфейс между МК и ПЛИС
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
DENth
Уважаемое сообщество! Есть следующий вопрос по взаимодействию ПЛИС и МК:
Имеем ARM7 LPC2468 и ПЛИС Cyclone 2. ПЛИС подключена к контроллеру внешней памяти ARMа. Данный интерфейс предназначен для работы с асинхронной памятью. Относительно ПЛИС сигналы Write, Read с МК асинхронны. На МК и ПЛИС поступает частота с единого генератора - 12Мгц, но в МК она перемножается до 72МГц - частота ядра. Длительность сигналов контроллера внешней памяти зависит от этой частоты. Частота 72МГц на ПЛИС не идет. Вопрос - как обеспечить максимальное быстродействие между МК и ПЛИС?

Read и Write пропускаю через два последовательных триггера для исключения метастабильного состояния. Но как поступать дальше? Использовать их для тактирования внутренних цепей ПЛИС для записи или чтения состояния регистров и памяти вроде как нельзя. Нужен явный клок. Но его нет с МК.

Сейчас получилось сделать так: стробирую эти сигналы внутренней частотой 72МГц, сформированной на PLL ПЛИС. Получаю сигнал длительностью один период частоты 72МГц. Этот сигнал подаю как сигнал разрешения на внутренние цепи. А клок 72МГц как клок на эти же цепи. Все работает. Но если в МК ускорять работу по этому интерфейсу, то всё перестает работать. Видимо пока я синхронизирую Read, Write внутри ПЛИС, МК уже захлопывает данные, а ПЛИС их еще не успела выставить. Стробировать большей частотой не получается, начинает ругаться временной анализатор.

Как сделать правильно?
olegras
Во-первых, лично я для исключения метастабильности использую защелкивание входных сигналов только на один триггер. До сих пор не подводило. Поэтому считаю, что два последовательных триггера - это лишняя перестраховка.
Во-вторых, у Вас частота данных на борту МК и частота защелкивания входнух данных на ПЛИС - одинаковые. Поэтому, если Вы защелкиваете Write, также и защелкивайте DATA_IN, а уже потом работайте с результатом в домене 72 МГц.
DASM
а что значит «ускорять»? И что именно перестает работать? Вы пишите данные с МК а потом забирает результат с ПЛИС? Какая латентность этой обработки? И честно гоаоря не вижу криминала стробы чтения записи подать на входы глобал клоков, а потом передать из на обработку в другой плисовый клоковый домен через фифо например. Также неясно ,что вы там наворотили, что уже на 72 мгц ругается анализатор.
Raven
Относящиеся к делу фрагменты кода - в студию! Тогда разговор будет конкретным, а помощь - быстрой и эффективной. Вроде ничего потенциально высокоценного в описанном интерфейсном модуле не предвидится, так что от его публикации никто не пострадает sm.gif.
olegras
Цитата(DASM @ Sep 1 2013, 10:46) *
И что именно перестает работать?

Правильный вопрос. Что значит "перестает работать"?
Я так понял - при однократном WRITE с МК - ПЛИС принимает данные корректно. При зацикливании этого процесса на МК - ПЛИС принимает абракадабру/нули/единицы/предыдущее значение/... Подчеркните нужное.
iosifk
Цитата(DENth @ Aug 31 2013, 18:34) *
Read и Write пропускаю через два последовательных триггера для исключения метастабильного состояния. Но как поступать дальше? Использовать их для тактирования внутренних цепей ПЛИС для записи или чтения состояния регистров и памяти вроде как нельзя. Нужен явный клок. Но его нет с МК.

Как сделать правильно?


Два триггера - это правильно.
А дальше усть варианты. Если ПЛИС значительно быстрее, чем МК, то с точки зрения МК все будет укладываться в один цикл "записи". А вот если их скорости примерно одинаковы, то тогда при чтении надо будет переходить к "пакетному" режиму. Т.е. при первом чтении в ПЛИС запишется адрес и перетактируются данные из памяти в выходной регистр, а при втором - данные уйдут в МК. И далее, если сделаете пост-инкремент адреса, то можно будет делать чтение берстом (пакетом)...
А более подробно - у меня на сайте "Краткий Курс", раздел CDC... Кстати и Вам, olegras тоже рекомендую...
olegras
Цитата(iosifk @ Sep 1 2013, 11:24) *
Два триггера - это правильно.
... раздел CDC... Кстати и Вам, olegras тоже рекомендую...

Читал, и постоянно пользуюсь. Насчет двух триггеров - я ведь не отрицаю и полностью подтверждаю. Я лишь говорю что если частоты двух доменов равны (а у DENth они равны) - то достаточно одного триггера. Но он должен быть! Во всяком случае, этот факт проверен много раз на практике на частотах до 100 МГц включительно.
DENth
Цитата(olegras @ Sep 1 2013, 08:46) *
Во-первых, лично я для исключения метастабильности использую защелкивание входных сигналов только на один триггер. До сих пор не подводило. Поэтому считаю, что два последовательных триггера - это лишняя перестраховка.
Во-вторых, у Вас частота данных на борту МК и частота защелкивания входнух данных на ПЛИС - одинаковые. Поэтому, если Вы защелкиваете Write, также и защелкивайте DATA_IN, а уже потом работайте с результатом в домене 72 МГц.


Частоты одинаковы, но источники частот разные. Не знаю - можно ли их считать синхронными друг другу. Обе частоты формируются PLL. Но одна в МК, другая в ПЛИС. Если завести обе частоты в SignalTap квартуса, то выглядят они синхронными друг другу, но можно ли достоверно сказать, что это так? Во-вторых в документации на МК нет временной диаграммы, связывающей частоту ядра с времянками чтения и записи по интерфейсу внешней памяти. Из-за этого всего не ясно - когда защелкивать входные данные и когда должны быть выставлены выходные для их правильного защелкивания в МК?

Привожу временные диаграммы чтения и записи МК, а также табличку с длительностями сигналов.




klop
Цитата(olegras @ Sep 1 2013, 11:27) *
Я лишь говорю что если частоты двух доменов равны (а у DENth они равны) - то достаточно одного триггера. Но он должен быть!


Да заявы пошли не шуточные. Ну так на всякий случай сообщаю что флопов должно быть как минимум два.
DENth
Цитата(DASM @ Sep 1 2013, 10:46) *
а что значит «ускорять»? И что именно перестает работать? Вы пишите данные с МК а потом забирает результат с ПЛИС? Какая латентность этой обработки? И честно гоаоря не вижу криминала стробы чтения записи подать на входы глобал клоков, а потом передать из на обработку в другой плисовый клоковый домен через фифо например. Также неясно ,что вы там наворотили, что уже на 72 мгц ругается анализатор.


Под ускорением подразумеваю увеличение количества циклов чтения/записи со стороны МК за единицу времени. В ARMе сделано так, что при этом длительности сигналов write, read уменьшаются с увеличением частоты обращений. Зависят от неких величин, которые приведены в табличке выше.

Стробы записи и чтения я как раз-таки завел на глобал клоки. При 72МГц анализатор пока не ругается, но при увеличении частоты стробирования начинаются проблемы. Код попробую подготовить, чтобы стало более понятнее.

Цитата(olegras @ Sep 1 2013, 11:03) *
Правильный вопрос. Что значит "перестает работать"?
Я так понял - при однократном WRITE с МК - ПЛИС принимает данные корректно. При зацикливании этого процесса на МК - ПЛИС принимает абракадабру/нули/единицы/предыдущее значение/... Подчеркните нужное.


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

Цитата(iosifk @ Sep 1 2013, 11:24) *
Два триггера - это правильно.
А дальше усть варианты. Если ПЛИС значительно быстрее, чем МК, то с точки зрения МК все будет укладываться в один цикл "записи". А вот если их скорости примерно одинаковы, то тогда при чтении надо будет переходить к "пакетному" режиму. Т.е. при первом чтении в ПЛИС запишется адрес и перетактируются данные из памяти в выходной регистр, а при втором - данные уйдут в МК. И далее, если сделаете пост-инкремент адреса, то можно будет делать чтение берстом (пакетом)...
А более подробно - у меня на сайте "Краткий Курс", раздел CDC... Кстати и Вам, olegras тоже рекомендую...


Считаем, что нужно построить систему с одним циклом записи, чтения. При пакетном производительность упадет в два раза? Это крайне не желательно.
Ваш курс по описанию временных ограничений с удовольствием читал и постоянно заглядываю при случае. Пожалуй, самое толковое, что есть в рунете по данной теме. Спасибо!
klop
Цитата(DENth @ Sep 1 2013, 12:19) *
Стробы записи и чтения я как раз-таки завел на глобал клоки. При 72МГц анализатор пока не ругается, но при увеличении частоты стробирования начинаются проблемы.

Конечно не ругается - ему ведь неизвестны времянки на СРАМ интерфейсе ЛПЦ
DENth
Цитата(klop @ Sep 1 2013, 13:26) *
Конечно не ругается - ему ведь неизвестны времянки на СРАМ интерфейсе ЛПЦ


Не могли бы вы подсказать, как анализатору их сообщить? А то у меня как и у анализатора видимо проблемы с этим =)
olegras
Цитата(klop @ Sep 1 2013, 13:09) *
Да заявы пошли не шуточные. Ну так на всякий случай сообщаю что флопов должно быть как минимум два.

Зря Вы иронизируете. Давайте разберемся. Может мы говорим о разных вещах.
Есть входные данные. Пусть будут write_in и data_in. Для простоты остальные сигналы не рассматриваем.
Код на VHDL:
CODE
port(
...
write_in: in std_logic; -- строб записи
data_in: in std_logic_vector(15 downto 0) -- данные
);

Есть сигналы
CODE
signal write_in_t: std_logic;
signal write_in_t0: std_logic;
signal data_in_t: std_logic_vector(15 downto 0);
signal data_in_t0: std_logic_vector(15 downto 0);
...
signal data_s: std_logic_vector(15 downto 0);

Пример первый - без защелки
CODE
...
if rising_edge(clk) then
if(write_in = '1') then
data_s <= data_in + x"abcd";
end if;
end if;

Пример второй - с одной защелкой
CODE
...
if rising_edge(clk) then
write_in_t <= write_in;
data_in_t <= data_in;
if(write_in_t = '1') then
data_s <= data_in_t + x"abcd";
end if;
end if;

Пример третий - с двумя защелками
CODE
...
if rising_edge(clk) then
write_in_t <= write_in;
write_in_t0 <= write_in_t;
data_in_t <= data_in;
data_in_t0 <= data_in_t;
if(write_in_t0 = '1') then
data_s <= data_in_t0 + x"abcd";
end if;
end if;

Я говорю про второй пример. Использую на практике несколько лет. На частотах до 100 МГц включительно. Еще ни разу не сбоило. При одинаковых частотах входного и внутреннего доменов - стабильность (и корректность) от сдвига фаз не зависит. Попробуйте сами.

DENth я похожую задачу делал для связки ЦСП от TI со Спартаном 3. Работало на частоте шины (между ними) 85 МГц. Представьте свою часть кода.

klop
Цитата(olegras @ Sep 1 2013, 13:08) *
Я говорю про второй пример. Использую на практике несколько лет. На частотах до 100 МГц включительно. Еще ни разу не сбоило. При одинаковых частотах входного и внутреннего доменов - стабильность (и корректность) от сдвига фаз не зависит. Попробуйте сами.

DENth я похожую задачу делал для связки ЦСП от TI со Спартаном 3. Работало на частоте шины (между ними) 85 МГц. Представьте свою часть кода.

Вау. А на данные то зачем синхронизаторы ставить?????

> от сдвига фаз не зависит
А вы их сдвигали?
olegras
Цитата(klop @ Sep 1 2013, 14:25) *
Вау. А на данные то зачем синхронизаторы ставить?????

> от сдвига фаз не зависит
А вы их сдвигали?


А Вы поставьте и проверьте. А сдвиг фаз смотрел на осцилле. В разных проектах и в разных реализациях - сдвиг был ессно разный. И вообще я поднял этот вопрос в ответ на "Видимо пока я синхронизирую Read, Write внутри ПЛИС, МК уже захлопывает данные, а ПЛИС их еще не успела выставить". Если защелкивать только WRITE (при чтении с МК) - так и будет. Но у DENth стробы заведены на клоковые входы. Значит он (предполагаю) принимает и передает данные по фронтам этих стробов, и значит у него проблема в другом. Выложит код - посмотрим.
Насчет двух флопов - я ведь не против. Ставьте хоть 15.
iosifk
Цитата(DENth @ Sep 1 2013, 13:19) *
Считаем, что нужно построить систему с одним циклом записи, чтения. При пакетном производительность упадет в два раза? Это крайне не желательно.


Это Вы неправильно поняли...
Обычно обмен данными производится пакетами, которые пишутся в ПЛИС подряд. Или из ПЛИС данные читаются подряд, а не в произвольном порядке...
А вот команды управления пишутся и читаются по "одиночным" адресам, но зато это делается относительно редко....
Вы сейчас хотите от асинхронного чтения-записи в ПЛИС перейти к синхронному...
Ну или по-другому... Если раньше, при записи МК выставлял данные и WR, то ПЛИС во время длительности WR успевала выработать свой внутренний строб и захватить данные... И под каждый цикл Вам нужны были и адрес и данные...
Теперь будет так; на входе по записи данных надо ставить регистр и в него под WR защелкивать данные. После чего МК идет дальше... А ПЛИС в это время делает CDC, т.е. от признака "была запись" формирует строб на системной частоте и системным же клоком под два такта делает запись в синхронное внутреннее ОЗУ. Под первый такт защелкивается адрес, а под второй - данные... Ну или если брать память "как есть", то ей скармливаются данные и адрес и сигнал разрешения... А дальше можно сделать так, чтобы при следующей записи адрес внутри ПЛИС инкрементился бы сам... Для этого из МК надо передавать признак "первая запись или последующие". Обычно для этого дополнительно берут старший разряд адреса. Скажем память на 10 адресов, тогда 11-й адрес - это тот самый признак.
Вот тогда первое слово на запись идет с признаком начала адреса пакета. При записи никакой дополнительной нагрузки на МК нет...
А при чтении - то же самое, но "в другую сторону"... Сначала запись с признаком адреса. данные игнорируются. Пауза между записью и первым чтением должна быть не менее латентности памяти в ПЛИС... Ну и дальнейшие чтения идут подряд. При этом регистр адреса в ПЛИС должен быть с постинкрементом. Следовательно, при пакете данных в 32 слова, получим только одну дополнительную запись. Т.к. она запись устанавливает регистр адреса...

А если и дальше идти по этому пути, то шину адреса можно мультиплексировать с данными, т.к. при чтении одна из этих шин все равно "отдыхает"...


DENth
Обещаный кусок кода. Пишу на AHDL. Проект достался в наследство. Изначально был написан так, что сигналы read, write МК шли непосредственно на клоковые входы регистров. Но поскольку это не верно, я решил все переделать. Однако, МК остался подключеным к ПЛИС по интерфейсу внешней памяти. Да и чего-нибудь более подходящего я всё равно найти не смог.

readflag_=rd;
readflag_.clk=12PLL.c0;

readflag[0]=readflag_;
readflag[0].clk=12PLL.c0;
readflag[1]=readflag[0];
readflag[1].clk=12PLL.c0;

rdx=!(!readflag[0] and readflag[1] and !bscnt.PLDCR[0]);
rdx.clk=!12PLL.c0;

-- где rd - сигнал read на ножке. readflag_, readflag[0] - D-триггеры для борьбы с метастабильностью. 12PLL.c0 - 72МГц;
-- rdx - результирующий строб длительностью 1 период 72МГц, !bscnt.PLDCR[0] - сигнал из подпроекта, разрешающий обработку.

writeflag_=wr;
writeflag_.clk=12PLL.c0;

writeflag[0]=writeflag_;
writeflag[0].clk=12PLL.c0;
writeflag[1]=writeflag[0];
writeflag[1].clk=12PLL.c0;

wrx=!(!writeflag[0] and writeflag[1] and !bscnt.PLDCR[0]);
wrx.clk=!12PLL.c0;

-- аналогично с записью

a_[]=a[];
a_[].clk=!12PLL.c0;
a_[].ena=latch_wr or latch_rd;

latch_rd=!readflag[0] and readflag[1];
latch_wr=!writeflag[0] and writeflag[1];

-- защелкивание адреса


дальше rdx и wrx поступают на все регистры и память ПЛИС в качестве сигналов разрешения. А 72МГц как клок на эти регистры и память.

Поясните мне мои ошибки, пожалуйста!


Цитата(olegras @ Sep 1 2013, 14:08) *
Я говорю про второй пример. Использую на практике несколько лет. На частотах до 100 МГц включительно. Еще ни разу не сбоило. При одинаковых частотах входного и внутреннего доменов - стабильность (и корректность) от сдвига фаз не зависит. Попробуйте сами.

DENth я похожую задачу делал для связки ЦСП от TI со Спартаном 3. Работало на частоте шины (между ними) 85 МГц. Представьте свою часть кода.


Смотрел-смотрел, но так толком и не смог понять. Не обучен я к сожалению ни VHDL ни Verilog'у. Еще с универа все проекты выполнялись на AHDL. А на работе, так получилось, что доставшиеся проекты также были на AHDL. Стимула для изучения других языков не было пока. Каюсь, надо совершенствоваться. Пока же я прошу Вас описать код более доступно, если это не очень трудно.

Цитата(iosifk @ Sep 1 2013, 15:48) *
Это Вы неправильно поняли...
Обычно обмен данными производится пакетами, которые пишутся в ПЛИС подряд. Или из ПЛИС данные читаются подряд, а не в произвольном порядке...
А вот команды управления пишутся и читаются по "одиночным" адресам, но зато это делается относительно редко....
Вы сейчас хотите от асинхронного чтения-записи в ПЛИС перейти к синхронному...
Ну или по-другому... Если раньше, при записи МК выставлял данные и WR, то ПЛИС во время длительности WR успевала выработать свой внутренний строб и захватить данные... И под каждый цикл Вам нужны были и адрес и данные...
Теперь будет так; на входе по записи данных надо ставить регистр и в него под WR защелкивать данные. После чего МК идет дальше... А ПЛИС в это время делает CDC, т.е. от признака "была запись" формирует строб на системной частоте и системным же клоком под два такта делает запись в синхронное внутреннее ОЗУ. Под первый такт защелкивается адрес, а под второй - данные... Ну или если брать память "как есть", то ей скармливаются данные и адрес и сигнал разрешения... А дальше можно сделать так, чтобы при следующей записи адрес внутри ПЛИС инкрементился бы сам... Для этого из МК надо передавать признак "первая запись или последующие". Обычно для этого дополнительно берут старший разряд адреса. Скажем память на 10 адресов, тогда 11-й адрес - это тот самый признак.
Вот тогда первое слово на запись идет с признаком начала адреса пакета. При записи никакой дополнительной нагрузки на МК нет...
А при чтении - то же самое, но "в другую сторону"... Сначала запись с признаком адреса. данные игнорируются. Пауза между записью и первым чтением должна быть не менее латентности памяти в ПЛИС... Ну и дальнейшие чтения идут подряд. При этом регистр адреса в ПЛИС должен быть с постинкрементом. Следовательно, при пакете данных в 32 слова, получим только одну дополнительную запись. Т.к. она запись устанавливает регистр адреса...

А если и дальше идти по этому пути, то шину адреса можно мультиплексировать с данными, т.к. при чтении одна из этих шин все равно "отдыхает"...


Архитектура нашего проекта выполнена таким образом, что обмен производится практически произвольно. МК пишет в регистры управления данные, означающие режим работы и запуск той или иной операции, будь то чтение или запись в ОЗУ ПЛИС. ПЛИС в зависимости от состояний регистров выполняет обработку. Результат обработки вычитывается МК перебиранием шины адреса условно случайным образом. То есть вычитал тут, прервался, вычитал там, закончил вычитавать из первого места. Пакетной передачи нет, хотя об этом можно подумать.
iosifk
Цитата(DENth @ Sep 1 2013, 21:21) *
..... Пишу на AHDL. Проект достался в наследство. ....

Смотрел-смотрел, но так толком и не смог понять. Не обучен я к сожалению ни VHDL ни Verilog'у. Еще с универа все проекты выполнялись на AHDL. А на работе, так получилось, что доставшиеся проекты также были на AHDL. Стимула для изучения других языков не было пока. Каюсь, надо совершенствоваться. Пока же я прошу Вас описать код более доступно, если это не очень трудно.

После этого можно только одно сказать, что серьезной отладкой проектов Вы заниматься не умеете. Увы!!! И до тех пор, пока не научитесь применять VHDL или Verilog о серьезном подходе к делу можно и не говорить....
DENth
Цитата(iosifk @ Sep 1 2013, 22:13) *
После этого можно только одно сказать, что серьезной отладкой проектов Вы заниматься не умеете. Увы!!! И до тех пор, пока не научитесь применять VHDL или Verilog о серьезном подходе к делу можно и не говорить....


Серьезной отладкой заниматься действительно не умею. Не так давно приступил к изучению TimeQuest, ибо надоело, что изменяя код одного подпроекта, отваливается другой. При помощи DesignAssistant постарался убрать часть варнингов, вызванных использованием недопустимых оборотов. Иду по пути совершенствования мелкими шагами. И результат ведь потихоньку да вырисовывается.

А что Вы мне можете рекомендовать? Взяться за изучение Verilog'а? Про него кратко читал. Но было бы лучше, если бы мне объяснили на пальцах - чем в корне он отличается от того же AHDL. На нем проще описать какой-то оборот? Или на нем можно описать то, чего на AHDL не получить никогда? Если то, что я описал допустим в 20 строках кода на верилоге можно описать одним оборотом - ведь не значит, что работать будет по разному? Или как?
Почему серьезный уровень - это только эти языки?
vladz
Цитата(DENth @ Sep 1 2013, 20:21) *
Поясните мне мои ошибки, пожалуйста!

Пока что пара очевидных вещей:
1. Из-за того что вы используете оба фронта тактовой частоты !12PLL.c0 и 12PLL.c0, вы поднимаете рабочую частоту проекта в 2 раза до 144МГц. Если логика получилась разбросана по кристаллу, данные могут не успевать за 144МГц тактовой и вызывать ошибки анализатора. Если возможно, то надо стараться использовать в проекте или блоке только один фронт, тода и разводчику PAR станет легче и вам анализировать проблемы станет проще.

2. Нарисуйте на бумаге диаграммы доступа МК к внешней памяти и проставьте длительности всех сигналов в тактах. Посчитайте на каком такте после начала wr и rd вы записываете или выставляете данные наружу. Очень может быть что придется время удержания wr и rd удлинить в программе МК.

И еще совет - постарайтесь давать сигналам осмысленные имена, иначе никто не захочет разбраться в этой мешанине символов. Глобальный клок просто не может называться 12PLL.c0, это должен быть просто clk, sys_clk или что-то еще с _clk если не лень набирать длинные имена. Сигнал разрешения обработки не должен именоваться !bscnt.PLDCR[0], измените на что-нибудь с _en/ enable.
olegras
Цитата(DENth @ Sep 1 2013, 21:21) *
... сигналы read, write МК шли непосредственно на клоковые входы регистров. Но поскольку это не верно ...

Это как раз верно. В Вашем случае ПЛИС для МК должна эмулировать поведение статического ОЗУ.
Будем двигаться поэтапно. Перечислите какие конкретно выводы EMC МК подключены к ПЛИС и как Вы их в ПЛИС обзываете.
iosifk
Цитата(DENth @ Sep 1 2013, 23:22) *
Серьезной отладкой заниматься действительно не умею. ....Почему серьезный уровень - это только эти языки?


Потому что МоделСим не понимает AHDL... А дальше читайте "Краткий Курс", главу про отладку...

Сколько лет проработал в техподдержке, столько не перестаю удивляться, когда получается ситуация такая, как эта...
Все что написано вообще здесь, всё обсуждение выглядит примерно так: "Ставлю компьютер на паровоз, гружу воду и дрова... А он все равно быстрее не идет и КПД не выше 12%... Почему??? Может кран какой до блеска начистить?"

А потому, что в "Гайке М3" написано:
1. Выбираем алгоритм
2. По алгоритму выбираем требования к железу...

Так вот. У Вас алгоритм случайного чтения внешней медленной памяти в программном режиме. В программном! А это значит, принципиально обработка данных сделана медленно...
Вот: "Результат обработки вычитывается МК перебиранием шины адреса условно случайным образом. То есть вычитал тут, прервался, вычитал там, закончил вычитавать из первого места. Пакетной передачи нет, хотя об этом можно подумать."

Память МК - асинхронная, память ПЛИС - синхронная... И Вы синхронную память ПЛИС подгоняете к асинхронному чтению.
А это значит, что за длительность сигнала чтения от МК внутри ПЛИС должно пройти как минимум 3-4 внутренних клока. А иначе синхронная внутренняя память не успеет выдать данные... А в это время МК стоит и ждет... И быстрее этот паровоз не поедет никогда!!! Смотрите минимальную длительность тактовых для памяти, умножайте на латентность по чтению и добавляйте импульсы на прохождение от памяти к выходу... И добавьте сюда время на "разворот шины"... И это будет предел. Все. Больше тут обсуждать нечего...

А если действительно хотите, чтобы паровоз ехал быстрее, то меняйте пункт №1... Подгоняйте режим работы МК к работе синхронной памяти. Включайте ДМА и переходите на пакетное чтение данных. И уже потом, в памяти МК производите обработку данных любым "случайным образом"... Ведь внутреннюю память МК читает на внутренних клоках, а это в несколько раз быстрее...
Для этого меняйте расположение данных в памяти ПЛИС так, чтобы их было удобно качать по ДМА пакетами. Как изменить порядок чтения-записи - я немного написал выше...
Вот только так можно сделать стык с МК быстрым. Другого способа - НЕТ!
А все ковыряния с фронтами, с сигналами и пр. только приведут к потере времени...

psL
Цитата(DENth @ Sep 1 2013, 21:21) *
Обещаный кусок кода. Пишу на AHDL.

readflag_=rd;
readflag_.clk=12PLL.c0;

readflag[0]=readflag_;
readflag[0].clk=12PLL.c0;
readflag[1]=readflag[0];
readflag[1].clk=12PLL.c0;

rdx=!(!readflag[0] and readflag[1] and !bscnt.PLDCR[0]);
rdx.clk=!12PLL.c0;

-- где rd - сигнал read на ножке. readflag_, readflag[0] - D-триггеры для борьбы с метастабильностью. 12PLL.c0 - 72МГц;
-- rdx - результирующий строб длительностью 1 период 72МГц, !bscnt.PLDCR[0] - сигнал из подпроекта, разрешающий обработку.

writeflag_=wr;
writeflag_.clk=12PLL.c0;

writeflag[0]=writeflag_;
writeflag[0].clk=12PLL.c0;
writeflag[1]=writeflag[0];
writeflag[1].clk=12PLL.c0;

wrx=!(!writeflag[0] and writeflag[1] and !bscnt.PLDCR[0]);
wrx.clk=!12PLL.c0;

-- аналогично с записью

a_[]=a[];
a_[].clk=!12PLL.c0;
a_[].ena=latch_wr or latch_rd;

latch_rd=!readflag[0] and readflag[1];
latch_wr=!writeflag[0] and writeflag[1];

-- защелкивание адреса


дальше rdx и wrx поступают на все регистры и память ПЛИС в качестве сигналов разрешения. А 72МГц как клок на эти регистры и память.

По идее период тактовой с PLL при таком дизайне д.б. как минимум вдвое выше чем время активности wr, rd
Вы пробовали асинхронно обмениваться (без тактирования)? т.е. например по низкому уровню сигнала записи (не по фронту)ШАД защелкивается в буферном регистре, по высокому уровню сигналы с выхода буферного регистра передаются уже далее в модуль обработки. Для чтения - наоборот.
ViKo
В LPC нельзя добавить тактов (ожидания) при записи, чтении? И сигнала WAIT не имеется?
DENth
Цитата(olegras @ Sep 2 2013, 10:11) *
Это как раз верно. В Вашем случае ПЛИС для МК должна эмулировать поведение статического ОЗУ.
Будем двигаться поэтапно. Перечислите какие конкретно выводы EMC МК подключены к ПЛИС и как Вы их в ПЛИС обзываете.



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

С МК идут как раз выводы wr - строб записи и rd - строб output enable. Но они не заведены на пины глобал клок ПЛИС. А также шина адреса [15..0] и шина данных [7..0]. Всё с точностью как описано в куске кода, который я привел выше. Выбор такого метода был вызван исходя из того, чтобы анализатор смог выдерживать временные ограничения.

Временные ограничения описал следующим образом:

create_clock -name {12mhz} -period 83.333 -waveform { 0.000 41.666 } [get_ports {12mhz}]
derive_pll_clocks
set_multicycle_path 2 -from [get_registers {a_[*]}] -to [get_registers {*}] -setup
set_multicycle_path 2 -from [get_registers {a_[*]}] -to [get_registers {*}] -hold


Цитата(ViKo @ Sep 2 2013, 13:16) *
В LPC нельзя добавить тактов (ожидания) при записи, чтении? И сигнала WAIT не имеется?


Задача - увеличить насколько возможно частоту обращений МК к ПЛИС в единицу времени. Эта величина задается некими переменными внутри МК, такими как WAITRD, WAITOEN, WAITWR и WAITWEN. А если их менять в меньшую сторону, то уменьшается и длительность самих стробов чтения/записи. При этом ПЛИС уже перестает успевать выставлять данные для МК и всё прочее. Вопрос мой был в том, как правильно описать взаимодействие МК и ПЛИС, так как сейчас нет уверенности, что всё сделано правильно. Хочется выжать из обмена еще чуточку =)

Цитата(psL @ Sep 2 2013, 12:45) *
По идее период тактовой с PLL при таком дизайне д.б. как минимум вдвое выше чем время активности wr, rd
Вы пробовали асинхронно обмениваться (без тактирования)? т.е. например по низкому уровню сигнала записи (не по фронту)ШАД защелкивается в буферном регистре, по высокому уровню сигналы с выхода буферного регистра передаются уже далее в модуль обработки. Для чтения - наоборот.


Длительность wr, rd с МК составляет несколько периодов частоты 72МГц, но сколько точно, програмист МК сказать не смог, из временных диаграмм МК этого тоже не видно. Асинхронно обмениваться пробовал. С этого все начиналось. Но только если я Вас правильно понял. Не совсем понятно, как сделать обработку не по фронту? Защелкивание в буфер ведь должно происходить по какаму-то клоку? Внутреннему?

Цитата(iosifk @ Sep 2 2013, 10:47) *
Потому что МоделСим не понимает AHDL... А дальше читайте "Краткий Курс", главу про отладку...


Продолжаю работать пока на Квартусе 9.1, благо там есть waveform editor, на конечном этапе использую SignalTap. Этого пока достаточно. Моделсим пока освоить не удалось. В том числе и из-за незнания VHDL.

Цитата(iosifk @ Sep 2 2013, 10:47) *
Вот только так можно сделать стык с МК быстрым. Другого способа - НЕТ!
А все ковыряния с фронтами, с сигналами и пр. только приведут к потере времени...


Спасибо за дельные советы! Придется пересмотреть подход к архитектуре.
Но сразу же возник маленький вопрос - наш МК поддерживает работу с динамической памятью. А ПЛИС может "стать" этой самой SDRAM? Ответ на этот вопрос я не смог найти. Все доступные IP функции как я понял реализованы для связи ПЛИС с физической SDRAM.
Victor®
Цитата(vladz @ Sep 1 2013, 23:54) *
Пока что пара очевидных вещей:
1. Из-за того что вы используете оба фронта тактовой частоты ....


Это одна из разновидностей всяческого зла...
(если это делать неправильно, а правильно только на DDR триггерах)
И практически всегда внутри проекта можно (и нужно) обойтись одним фронтом.
Не хватает частоты - ставьте PLL x2.

Объяснять не буду, обсуждалось

P.S.
FIFO вас спасет
olegras
Что-то я запутался. То есть у Вас когда то была одна плата (наследство), на которой wr и oe МК были заведены на клоковые входы ПЛИС (это один подход к взаимодействию). Теперь у Вас другая плата, на которой эти же выходы МК заведены на IO ПЛИС (это совсем другой подход к взаимодействию) и Вы планируете остановиться на этой плате. Насчет плат я правильно понял? Или Вы связали два кита (т.е. есть возможность заводить МК на произвольные пины ПЛИС)? Просто хочется понять на чем Вы остановились чтобы двигаться дальше.
psL
Цитата(DENth @ Sep 2 2013, 17:02) *
Длительность wr, rd с МК составляет несколько периодов частоты 72МГц, но сколько точно, програмист МК сказать не смог, из временных диаграмм МК этого тоже не видно. Асинхронно обмениваться пробовал. С этого все начиналось. Но только если я Вас правильно понял. Не совсем понятно, как сделать обработку не по фронту? Защелкивание в буфер ведь должно происходить по какаму-то клоку? Внутреннему?

У 573 регистра, например, нет никакого клока.
DENth
Цитата(olegras @ Sep 2 2013, 17:21) *
Что-то я запутался. То есть у Вас когда то была одна плата (наследство), на которой wr и oe МК были заведены на клоковые входы ПЛИС (это один подход к взаимодействию). Теперь у Вас другая плата, на которой эти же выходы МК заведены на IO ПЛИС (это совсем другой подход к взаимодействию) и Вы планируете остановиться на этой плате. Насчет плат я правильно понял? Или Вы связали два кита (т.е. есть возможность заводить МК на произвольные пины ПЛИС)? Просто хочется понять на чем Вы остановились чтобы двигаться дальше.


Не-не-не... Я видимо запутал Вас тем, что не совсем правильно объяснил. Прошу простить. Я имел ввиду не то, что стробы wr и oe заводились на клоковые входы, а то, что в редакторе назначений им был присвоен Global Clock. Регистры на входах пинов wr и oe, а также адресные a_[] были назначены fast input регистрами. Все выводы МК в итоге на IO ПЛИС. Плата сейчас на этапе корректировки. Можно переподключить. Это может на что-то повлиять?

Цитата(psL @ Sep 2 2013, 17:36) *
У 573 регистра, например, нет никакого клока.


Ушел гуглить описание сего девайса...
Corner
Решал подобную задачку на связке 5576ХС+1986ВЕ91. Быстрее чем на 6 МГц стабильно не работает в принципе. Благо шина 32 бит.
olegras
Для Вашего МК (по даташиту) я бы делал так (пока в общих чертах, завтра если будет время - постараюсь набросать):
на внешних портах ПЛИС имеем
- we, заводим на клоковый вход регистра записи (данные и адрес записи, МК -> ПЛИС);
- bls (один из них, скорей всего младший), заводим на клоковый вход регистра чтения (данные и адрес чтения, ПЛИС -> МК);
- oe заводим на управление двунаправленой шиной данных, и на вход разрешения регистра чтения (а может и записи);
- двунаправленную шину данных;
- шину адреса;
- cs (а вдруг Вы не к ПЛИС обращаетесь?).
Внутренним клоком стробируем выход регистра записи и вход регистра чтения (формируем "свои" регистры в клоковом домене);
на внутренних портах этого модуля имеем (выход - в логику ПЛИС, вход - от логики ПЛИС) сигналы в домене своего клока:
- собственно сам внутренний клок ПЛИС (вход);
- адрес записи (выход - адрес, по которому произошла запись);
- сигнал, говорящий о факте записи (выход, выставляется при записи);
- данные записи (выход);
- адрес чтения (выход - адрес по которому МК собирается прочитать из ПЛИС, может объединим с адресом записи);
- сигнал, говорящий о факте чтения (выход, выставляется при чтении);
- данные для чтения (вход, выставляется ПЛИС по адресу чтения).
Повторюсь - пока это в общих чертах. Вы тоже подумайте. Вам достаточно этих сигналов?
В любом случае таймингами EMC МК придется поиграться - обычная процедура при связках двух камней.
DENth
Цитата(olegras @ Sep 2 2013, 19:59) *
Для Вашего МК (по даташиту) я бы делал так (пока в общих чертах, завтра если будет время - постараюсь набросать):
на внешних портах ПЛИС имеем
- we, заводим на клоковый вход регистра записи (данные и адрес записи, МК -> ПЛИС);
- bls (один из них, скорей всего младший), заводим на клоковый вход регистра чтения (данные и адрес чтения, ПЛИС -> МК);
- oe заводим на управление двунаправленой шиной данных, и на вход разрешения регистра чтения (а может и записи);
- двунаправленную шину данных;
- шину адреса;
- cs (а вдруг Вы не к ПЛИС обращаетесь?).
Внутренним клоком стробируем выход регистра записи и вход регистра чтения (формируем "свои" регистры в клоковом домене);
на внутренних портах этого модуля имеем (выход - в логику ПЛИС, вход - от логики ПЛИС) сигналы в домене своего клока:
- собственно сам внутренний клок ПЛИС (вход);
- адрес записи (выход - адрес, по которому произошла запись);
- сигнал, говорящий о факте записи (выход, выставляется при записи);
- данные записи (выход);
- адрес чтения (выход - адрес по которому МК собирается прочитать из ПЛИС, может объединим с адресом записи);
- сигнал, говорящий о факте чтения (выход, выставляется при чтении);
- данные для чтения (вход, выставляется ПЛИС по адресу чтения).
Повторюсь - пока это в общих чертах. Вы тоже подумайте. Вам достаточно этих сигналов?
В любом случае таймингами EMC МК придется поиграться - обычная процедура при связках двух камней.


Про we и bls согласен. Но заводить ли "oe" отдельно? Для выбора направления шины данных на выход из ПЛИС мне кажется можно использовать тот же bls. Задержка распросранения этого сигнала внутри ПЛИС позволит, думаю, выдержать требования по удержанию данных на шине для МК (перед переходом в третье состояние). К тому же из PDF на МК для себя сделал заключения, что сигналы bls и oe практически идентичны друг другу.
CS в данном случае не требуется. На шине сидят только МК и ПЛИС.
Дальше уже не совсем прозрачно - операция чтения/записи будет происходить за один цикл МК? И требуется ли подавать We и bls на клоковые пины ПЛИС?

olegras
Цитата(DENth @ Sep 2 2013, 22:08) *
... операция чтения/записи будет происходить за один цикл МК? И требуется ли подавать We и bls на клоковые пины ПЛИС?

Так как частота сигналов на шине EMC МК ниже чем системная частота МК (подозреваю, что минимум в два раза), а системная частота ПЛИС равна системной МК - то скорей всего да. То есть не за один цикл МК, а за один цикл ЕМС МК.
we подавать на клоковый вход для того, чтобы не ПЛИС защелкивала шину по своим клокам и по уровню we, а МК в ПЛИС защелкнул своим we.
Набросал часть записи (МК -> ПЛИС)
Нажмите для просмотра прикрепленного файла.
Часть чтения позже, скорей всего завтра (завал на работе). Синхронизаторы на шинах данных и адреса скорей всего можно будет убрать - данные и адрес для ПЛИС уже гарантировано защелкнуты. Опыты покажут. ое и bls - не одно и тоже. oe устанавливается только при записичтении, а bls каждый раз - и при записи и при чтении.
DASM
--
olegras
Цитата(DASM @ Sep 3 2013, 11:00) *
А что такой схемке с метастабильностью ? У вас из тригерров с WR clock идет прямо на тригерры от ПЛИС клок. Или я невнимательно читал предыдущее ?

Я имел ввиду что СКОРЕЙ ВСЕГО можно будет оставить только синхронизатор для wrx. Потому что на момент синхронизации wrx по clk - адрес и данные (защелкнутые по we) уже не в метастабильном состоянии.

А еще можно подумать задействовать двухпортовое ОЗУ. В порт А МК будет записывать в домене we. Зная адрес записи, ПЛИС по порту B будет забирать в домене clk.
DENth
Цитата(olegras @ Sep 3 2013, 10:14) *
Набросал часть записи (МК -> ПЛИС)


Действительно хорошее решение. Я проанализировал, набросал тестовый проектик. По редактору диаграмм все отлично работает. Если для wr использовать два последовательных триггера-синхронизатора, то полученный строб wrx как раз то что нужно для входов разрешения внутренней логики. Его период 2 клока внутренней частоты. Эту же частоту подаем на клоковые входы внутренней логики ПЛИС.
С сигналом rd думаю можно поступить аналогично. Тактируем входной регистр, далее на два синхронизатора. Так как основная задача читать внутренне ОЗУ ПЛИС, подаем его на вход разрешения чтения двухпортовой памяти. Клок при чтении опять же внутренний, тот же что и при записи. С регистрами для чтения вроде бы тоже не должно возникнуть сложностей. Сейчас регистры, которые необходимо читать, выбираются через CASE. Перебирается адрес. Адрес храним в регистре. В зависимости от адреса на шину данных выставляем данные соответствующего регистра. Шину на выход держим опять же сигналом rd.
Для данных и адреса при записи синхронизаторы думаю ни к чему. Согласен с Вашей мыслью, что метестабильного состояния здесь быть не должно. Данные при чтении с того же ОЗУ выставятся сами при условиях, описанных выше. Держим шину данных на выход в течениии длительности rd.
Остается лишь вопрос с регистром для хранения адреса чтения. Нельзя ли использовать один и на запись и на чтение, а тактировать его замешанными между собой wr и rd? !wr or !rd. В рекомендациях по правильному описанию проектов ведь допускается пропускать клок через комбинаторную логику, использующую два входа.

Завтра попробую откорректировать проект и посмотреть результат. Полученный код выложу.
olegras
С чтением всегда проблем больше. Приходится играться с таймингами МК. Часть чтения для начала такая:

Нажмите для просмотра прикрепленного файла

Последовательность при чтении: защелкивание адреса по bls -> выработка rdx -> выставление по адресу addr_rx данных на шину data_rd. На все это МК дает время не больше чем toeloeh, которое можно (и нужно) регулировать битами WAITOEN и WAITRD. Пробуйте.
kenning
Цитата(Corner @ Sep 2 2013, 18:22) *
Решал подобную задачку на связке 5576ХС+1986ВЕ91. Быстрее чем на 6 МГц стабильно не работает в принципе. Благо шина 32 бит.

Можно подробнее о том, как была решена эта задача?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.