Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ПЛИС + SRAM
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
%-)
есть порт для ввода данных из хост-процессора в ПЛИС (запись в ПЛИС)

к ПЛИС подключена SRAM

нужно организовать запись в SRAM через ПЛИС.
при этом адрес на память выставляет сама ПЛИС.

сделано вот так:

Код
SRAM_D<=Port_D;      --линии данных порта ПЛИС соединяем с линиями данных SRAM
SRAM_A<=Address;    --линии адреса SRAM соединены со счётчиком ПЛИС
SRAM_CS<=Port_CS;  --линия выбора SRAM соединена с линией порта ПЛИС
SRAM_OE<='1';          --чтение не используется
SRAM0_WE<=Port_WE; --линия разрешения записи SRAM соединена с линией порта ПЛИС

process(Port_WE) --увеличение адреса на 1
begin
if falling_edge(Port_WE) then
  if Port_CS='0' then
   if Address=1000 then
    Address<=(others => '0');
   else
    Address<=Address+1;
   end if;
  end if;
end if;
end process;


По времянкам.

Tsetup=20нс
Thold=20нс
Twrite=20нс

Тем не менее, в силу каких-то обстоятельств(возможно когда на линии данных 0xFFFF) ИНОГДА происходит пропуск увеличения адреса - он как бы тот же.

Прошу покритиковать и обсудить код. А также причины, вызвавшие сей эффект
Builder
Цитата(%-) @ Nov 27 2009, 04:49) *
По времянкам.

Времянка укладывается в рекомендации на хост процессор и SRAM? Сами по себе 20 нан ничего не гарантируют.
Цитата(%-) @ Nov 27 2009, 04:49) *
Тем не менее, в силу каких-то обстоятельств(возможно когда на линии данных 0xFFFF) ИНОГДА происходит пропуск увеличения адреса - он как бы тот же.

Может земля между устройствами плохая? Попробуйте её улучшить, напаяв доп шину.
%-)
Цитата(Builder @ Nov 27 2009, 05:22) *
Времянка укладывается в рекомендации на хост процессор и SRAM? Сами по себе 20 нан ничего не гарантируют.


с лихвой! ещё как. запас в 2 раза (понизил скорость обмена)

память 10нс, времянка для процессора вполне "низкочастотная"

выскажу свою мысль.

дело в том, что может такой подход (как я описал выше) не совсем корректен, так как адрес на SRAM выставляется фактически в момент опускания строба записи,
а должен был выставлен намного раньше!
в итоге имеют место "данные, записанные не в тот адрес"

ИМХО нужно по опусканию CS подсчитывать адрес, но тут может возникнуть проблема с дешифрацией адресного бита типа "регистр/память", так как неизвестно будет ли установлен этот адресный бит "регистр-память" РАНЬШЕ чем произойдёт опускание CS.

в общем гемор ещё тот
BSV
Нужно в каждом цикле обращения выполнять операции с памятью по ТЕКУЩЕМУ адресу, а инкрементировать его ПОСЛЕ выполнения операции. Это обычная практика, тогда не будет проблем со времянками.
P.S. В Вашей теме про ПЛИС и процессор я уже писал, что запись по спаду строба записи - это неправильно, но Вы упорно продолжаете это делать...
%-)
Цитата(BSV @ Nov 27 2009, 08:08) *
Нужно в каждом цикле обращения выполнять операции с памятью по ТЕКУЩЕМУ адресу, а инкрементировать его ПОСЛЕ выполнения операции. Это обычная практика, тогда не будет проблем со времянками.
P.S. В Вашей теме про ПЛИС и процессор я уже писал, что запись по спаду строба записи - это неправильно, но Вы упорно продолжаете это делать...


ваш пример:

Код
process(AWEn)
begin
  if (AWEn'event and AWEn = '1') then
    if (CS='0' and A='0' and  D(15 downto 12) = "0101") then
      Y<=D(7 downto 0);
    end if;
    ...
  end if;
end process;


всё хорошо, но есть неуверенность, что в момент подымания AWE будет актуален A (возможно он изменится)

кстати, когда CS=1, то каким будет сигнал на линии A (адрес со стороны процессора) - последний или Z-состояние?

ниже времянка той памяти с которой идёт работа.

в момент поднятия WE, данные ещё актуальны. тогда какое мы имеем право изменять адрес во время фронта WE ? (rising edge?)

ведь он уже должен быть стабилен и актуален до поднятия CS.

прошу разъяснить если заблуждаюсь.

P.S. вот ещё что надумалось.

можно увеличивать адрес по rising_edge(CS). Приемущество в том что память защищена от записи в этот момент (Thold>0, WE=1)

исправил процесс. позже потестирую

Код
process(Port_CS,Port_A,Port_WE)
begin
--Register CS=0,WE=0
if Port_CS='0' then
  if Port_WE='0' then
   case Port_D(15 downto 12) is
    when "1000" =>
     R_M:=Port_D(2 downto 0);
    when "1001" =>
     if VBlank='0' then
      R_P:=Port_D(0);
     end if;
    when "1010" =>
     R_W:=Port_D(8 downto 0);
     W2:='0'&R_W(8 downto 1);
     X0:="010100000"-W2;
     X1:="010011111"+W2;
     X:=X0;
    when "1011" =>
     R_H:=Port_D(7 downto 0);
     H2:='0'&R_H(7 downto 1);
     Y0:="01111000"-H2;
     Y1:="01110111"+H2;
     Y:=Y0;
    when others =>
     null;
   end case;
  end if;
else
--VideoRAM CS=1,A ---|___
  if rising_edge(Port_A) then
   if X=X1 then
    X:=X0;
    if Y=Y1 then
     Y:=Y0;
    else
     Y:=Y+1;
    end if;
   else
    X:=X+1;
   end if;
   WriteAddress<=("101000000"*Y)+X;
  end if;  
end if;
end process;


в vhdl-коде решил Port_A превратить в CS для данных.

тоесть:

Port_CS=0 - разрешение пиать в регистры
Port_A=0 - разрешение увеличивать адрес памяти
Port_WE - разрешение записи (общий)
sazh
Цитата(%-) @ Nov 27 2009, 03:49) *
Прошу покритиковать и обсудить код. А также причины, вызвавшие сей эффект


Насадите все эти сигналы на глобальный клок, для которого они все будут одинаковой приоритетности, сразу всех зайцев убъете
Builder
Цитата(%-) @ Nov 27 2009, 06:25) *
дело в том, что может такой подход (как я описал выше) не совсем корректен, так как адрес на SRAM выставляется фактически в момент опускания строба записи,
а должен был выставлен намного раньше!
в итоге имеют место "данные, записанные не в тот адрес"

Вообще, когда я спрашивал про времянку, я имел ввиду не просто, 10 нан память, 20 нан ограничения - всё пучком.
Вигушки, нужно учесть все сетапы и холды памяти. Т.е. если у Вас идёт строб, то нужно посмотреть сколько времени сигнал идёт от этого строба обратно на адресса памяти. Хватает ли того времени что остаётся для нормальной работы памяти. И что-то мне одсказывает что не всё там у Вас стыкуется.
Перепроверьте ещё раз. Ну больше запаса будет, если действительно инкрементпировать после записи, а не перед.
%-)
проблема почти выявлена.

инкремент адреса иногда не срабатывает когда цвет близок к белому (большинство битов =1)

заземлил кабель наконец-то - ничего не дало.

действительно, после подъёма WE времянка укороченная. Удалось Tsetup=1, Twrite=1, Thold=0, тоесть 2 такта @150 МГц => 75МГц

но как только встречается белый цвет - всё глюкает - кадр крутится слеванаправо и сверхувниз...

уже мозг сломал, но причину ЯВНО не нашёл sad.gif smile3046.gif

на текущий момент:

Код
process(Port_WE,Port_CS)
variable W2:std_logic_vector(8 downto 0);
variable X0:std_logic_vector(8 downto 0);
variable X1:std_logic_vector(8 downto 0);
variable X:std_logic_vector(8 downto 0);
variable H2:std_logic_vector(7 downto 0);
variable Y0:std_logic_vector(7 downto 0);
variable Y1:std_logic_vector(7 downto 0);
variable Y:std_logic_vector(7 downto 0);
begin
if rising_edge(Port_WE) then
  if Port_CS='0' then
   --Register
   if Port_A='0' then
    case Port_D(15 downto 12) is
     when "1000" =>
      R_M:=Port_D(2 downto 0);
     when "1001" =>
      if ((R_M(2)='0' and VBlank='0') or (R_M(2)='1' and Blank='0')) then
       R_P:=Port_D(0);
      end if;
     when "1010" =>
      R_W:=Port_D(8 downto 0);
      W2:='0'&R_W(8 downto 1);
      X0:="010100000"-W2;
      X1:="010011111"+W2;
      X:=X0;
     when "1011" =>
      R_H:=Port_D(7 downto 0);
      H2:='0'&R_H(7 downto 1);
      Y0:="01111000"-H2;
      Y1:="01110111"+H2;
      Y:=Y0;
     when others =>
      null;
    end case;
   --VideoRAM
   else
    WriteAddress<=("101000000"*Y)+X;
    if X=X1 then
     X:=X0;
     if Y=Y1 then
      Y:=Y0;
     else
      Y:=Y+1;
     end if;
    else
     X:=X+1;
    end if;
   end if;
  end if;
end if;
end process;
des00
Цитата(%-) @ Nov 27 2009, 03:02) *
уже мозг сломал, но причину ЯВНО не нашёл sad.gif smile3046.gif


Вы меня простите, но все это напоминает мне одну народную мудрость : мыши плакали, кололись, но продолжали жрать кактус (с) %)
%-)
значит так.

1) буфер чисто на данные ставить нельзя - так как стробы приходят раньше чем данные на выводах буфера. тоесть задержка.
не работает даже с тормозными времянками

2) отпаяв буфер, перепроверил ещё раз. всё пашет как надо. ошибка была в счётчике строк.

3) так и не понятно - в какой момент времени можно менять адрес
снова прикрепляю картинку - ткните носом плиз - на рисунке - КОГДА МОЖНО МЕНЯТЬ АДРЕС???

4) пока сделана отдельная команда изменить адрес
sazh
Цитата(%-) @ Nov 29 2009, 07:25) *
3) так и не понятно - в какой момент времени можно менять адрес
снова прикрепляю картинку - ткните носом плиз - на рисунке - КОГДА МОЖНО МЕНЯТЬ АДРЕС???

4) пока сделана отдельная команда изменить адрес


А кто его знает, когда можно. Вы внедрились в процесс записи, самостоятельно манипулируя адресом.
Что мешает, например зафиксировав истинные адрес, данные от процессора, самому сформировать импульсы wr_n, cs_n на память и en на счетчик адреса в разах глобального клока. (В одном цикле записи от процессора)
%-)
Решил вникнуть в синхронный дизайн и сделать обработку следующим образом.

сигналы с процессора на ПЛИС:

CLKOUT - синхронизация для шины
Port_A - адресный бит (0 - регистры, 1 - увеличение адреса)
Port_D - данные
Port_WE - строб записи (активен когда 0)

сигналы с ПЛИС на SRAM:

SRAM_A - биты адреса SRAM
SRAM_D - данные
SRAM_WE - строб записи

Картинка с времянками ниже. Кажный setup по 2 clk (clk=133Мц) - чтоб ПЛИС гарантированно захватила уровни сигналов.

Автомат наподобие, как Shtirlits давал в соседней теме:

Код
signal state:std_logic:='0'; --начальное состояние

--коммутируем шины: адреса, данных
SRAM_D<=Port_D when (Port_A='1') else (others => 'Z'); --когда Port_A=1
SRAM_A<=WriteAddress;

process(CLKOUT)
begin

if falling_edge(CLKOUT) then
if (state='0' and Port_CS='0' and Port_WE='0' and Port_A='0') then --если Port_CS=0 и Port_WE=0 и Port_A=0 и состояние=0,  то данные актуальны для записи врегистры.
   state<='1'; --следующее состояние для инкремента адреса
  
   case Port_D(15 downto 12) is --запись в регистры (формируют старшие 4 бита)
    when "0000" =>
     reg_0<=Port_D(7 downto 0); --запись в регистр 0x0000
    when "0001" =>
     reg_1<=Port_D(7 downto 0); --запись в регистр 0x1000
    ....
   end case;
end if;

if (state='1' and Port_CS='0' and Port_WE='1' and Port_A='1') then --если Port_CS=0 и Port_WE=1 и Port_A=1 и состояние=1(тоесть уже была запись в регистр или SRAM), то записть в SRAM запрещена - можно менять адрес
  state<='0'; --следующее состояние для записи в память или регистры

  WriteAddress<=WriteAddress+1; --увеличиваем адрес на 1

end if;

SRAM_CS<=Port_CS; --коммутируем выбор SRAM
SRAM_WE<=Port_WE; --коммутируем разреш. записи

end if;

end Process;


CLKOUT - берется с платы процессора(к его лапке резистор 33 Ом) и 12-см проводом ко входу ПЛИС.

Прошу покритиковать. Имеет ли право дизайн на жизнь, или нужно изменить?
alevnew
Цитата(%-) @ Nov 27 2009, 15:02) *
инкремент адреса иногда не срабатывает когда цвет близок к белому (большинство битов =1)


По моему типичный глюк "ground bounce" - плохая земля между FPGA и памятью.
Практически один в один ситуация была. Лечилась пропайкой доп. земли между FPGA и другой микрухой (памятью в вашем случае).

Смею предположить, что плата - двухслойка? Я прав?
%-)
Цитата(alevnew @ Dec 1 2009, 11:06) *
По моему типичный глюк "ground bounce" - плохая земля между FPGA и памятью.
Практически один в один ситуация была. Лечилась пропайкой доп. земли между FPGA и другой микрухой (памятью в вашем случае).

Смею предположить, что плата - двухслойка? Я прав?


Плата с процессором - 4 слойка
Плата с ПЛИС - отладочная от Terasic. Тоже вроде 4 слоя(не менее)

Соединены ленточным кабелем длиной 12см + 8 см на печатке до ПЛИС + 3 см до процессора на плате

кабель в золотинке и он за GND-нен.

Народ, выскажитесь по моему синхронному автомату.
Будет жить? rolleyes.gif
sazh
Цитата(%-) @ Dec 1 2009, 10:11) *
Будет жить?


Счетчик адреса кто обнуляет?
В rtl посмотрите (он на иностранном языке)
%-)
я в стадии крайнего офонарения!!!

простейший автомат с 2-мя состояниями не работает!!!

Он должен писать значения в регистры, когда A=0,WE=0, CS=0

Clk=50MHz, ширина WE=10MHz, остальные ещё меньше по частоте


помогите плиз...

Код
process(Clk)
begin
if rising_edge(Clk) then
   if State='0' then
    if Port_CS='0' and Port_A='0' and Port_WE='0' then
     case Port_D(15 downto 12) is
      when "0010" =>
       if VBlank='0' then                                 --0x2000|P
        R_P<=Port_D(0);
       end if;
      when "0011" =>                                 --0x3000|X0
       R_X0<=Port_D(8 downto 0);
      when "0100" =>                                 --0x4000|X1
       R_X1<=Port_D(8 downto 0);
      when "0101" =>                                 --0x5000|Y0
       R_Y0<=Port_D(7 downto 0);
      when "0110" =>                                 --0x6000|Y1
       R_Y1<=Port_D(7 downto 0);
      when others =>null;
     end case;
     State<='1';
    end if;
   else
    if Port_WE='1' then
     State<='0';
    end if;
   end if;
end if;
end process;
%-)
сделал синхронную нарезку от внешнего кварцевого генератора 50мгц

автомат дышит, но по-прежнему иногда ложно срабатывают регистры.

Код
process(Clk)
begin
if rising_edge(Clk) then
  CE<=Port_CE;
  WE<=Port_WE;
  A<=Port_A;
  D<=Port_D;
end if;
end if;

process(Clk)
begin
if rising_edge(Clk) then
  if State='0' then
   if CE='0' and WE='0' then
    if A='0' then --запись в регистры
     case D(15 downto 12) is
      when "0000" =>
       Register0<=D(7 downto 0);
. . .
      when "0111" =>
       Register7<=D(7 downto 0);
     end case;
    else --увеличение адреса
     WriteAddr<=WriteAddr+1;
    end if;
    State<='1'; --следующее состояние - дождёмся завершения передачи
   end if;
  else
   if CS='0' and WE='1' then
    State<='0';
   end if;
  end if;
end if;
end process;    

process(Clk)
begin
if rising_edge(Clk) then
  SRAM_CE<=CE;
  SRAM_WE<=WE;
  SRAM_A<=WriteAddr;
  SRAM_D<=D;
end if;
end process;


Это позволило исключить ложные записи в память, но регистры глючат - к ним не обращаются, а они срабатывают

Чего ещё не хватает в коде? 1111493779.gif
des00
Цитата(%-) @ Dec 6 2009, 20:06) *
сделал синхронную нарезку от внешнего кварцевого генератора 50мгц


для шины на 133МГц ? как то слишком оптимистично, ИМХО при ваших tsu/twr/th надо не менее 100МГц

Цитата
автомат дышит, но по-прежнему иногда ложно срабатывают регистры.
Это позволило исключить ложные записи в память, но регистры глючат - к ним не обращаются, а они срабатывают


я бы привязывался не к уровню сигнала we, а при th = 1 к его заднему фронту
%-)
Цитата(des00 @ Dec 7 2009, 08:23) *
для шины на 133МГц ? как то слишком оптимистично, ИМХО при ваших tsu/twr/th надо не менее 100МГц


Сорри, забыл написать - что клок 50мгц с кварцевого генератора. Времянки записи растянуты так чтоб угодить в очко:

Tsetup=133mhz/4=33 MHz 4clk
Twrite=133/4=33 MHz 4clk
Thold=0

Цитата(des00 @ Dec 7 2009, 08:23) *
я бы привязывался не к уровню сигнала we, а при th = 1 к его заднему фронту


объясните пожалуйста подробно, о чём речь идёт - о записи в регистр или увеличении адреса памяти?

мне ещё писали что нарезать данные и адрес не надо. Только CS и WE. так?


прошу обсудить такой вариант с задним фронтом и без нарезки address/data:

THold=3clk 133/3=44.3 МГц
TWrite=4 clk =33.3 МГц
Tsetup=1clk (сделать =0clk невозможно - времянка BF533)

Код
--CLK=50MHz

process(Clk)
begin
if rising_edge(Clk) then
  CE<=Port_CE;
  WE<=Port_WE;
  A<=Port_A;
end if;
end if;

process(WE)
begin
if rising_edge(WE) then --запись по заднему фронту
   if CE='0' then
    if A='0' then --запись в регистры
     case Port_D(15 downto 12) is
      when "0000" =>
       Register0<=D(7 downto 0);
. . .
      when "0111" =>
       Register7<=D(7 downto 0);
     end case;
    else --увеличение адреса
     WriteAddr<=WriteAddr+1;
    end if;
   end if;
  end if;
end process;    

--просто без нарезки, так как CE, WE - уже нарезаны
  SRAM_CE<=CE;
  SRAM_WE<=WE;
  SRAM_A<=WriteAddr;
  SRAM_D<=D;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.