Forum: FPGA, VHDL & Co. aus RAM kommen falsche Daten raus


von Richard (Gast)


Lesenswert?

Hy, ich habe ein Projekt wo ich Daten zuerst ins RAM schreibe und wenn 
dieses voll sollen sie ins EEPROM geleert werden..

Bisher funktioniert es, dass die Daten richtig ins RAM kommen jedoch vom 
RAM kommen zu gänze die falschen Daten (ich vermute stark,dass nur die 
letzte Adresse ausgegeben wird....ich würde mich sehr freuen wenn mir da 
jemand helfen könnte denn selbst finde ich den Fehler einfach nicht

Hier der Code vom RAM:(welcher so funktioniert wie er sollte):

process(Clk_i,Reset_n_i)
begin
    if(Reset_n_i = '0')then
      Data_o <= (others => '0');          -- Reset Data output
      ram <= (others => (others =>'0'));  -- Reset RAM
    elsif(rising_edge(Clk_i)) then
      if(WriteEnable_i = '1') then
       ram(to_integer(unsigned(Address_i))) <= Data_i;  -- Write Data_i 
to RAM
      else
       Data_o <= ram(to_integer(unsigned(Address_i)));  -- Read RAM
      end if;
    end if;
end process;

end rtl;

und hier mein Code welcher dafür zuständig ist die Daten vom RAM zum 
SPI(EEPROM) zu leiten:

when stRAM2EEPROM =>
          CommandE_o     <= write_c;    -- SPI -Command -->Write
          CommandR_o    <= "0000";
          ControlR_o    <= "00000000";
          Writeenable_o <= '0';
          state         <= stRAM2EEPROM_Addr;
          CountAddress  <= (others =>'0');
          count         <= (others =>'0');

        when stRAM2EEPROM_Addr =>
          if(AddrWrDone_i = '1') then
            state        <= stRAM2EEPROM_Data;
          else
            DataEEPROM_o <= std_logic_vector(CountAddress);
          end if;


        when stRAM2EEPROM_Data =>
          if(DataWrDone_i= '1') then
            if(CountAddress ="11111111") then
                state <= stCAN2RAM;
            else
                CountAddress <= CountAddress+1;
                state <= stRAM2EEPROM_Addr;
              end if;
            else

            DataEEPROM_o  <= DataRAM_i;
          end if;

nochmals im Voraus ein Dankeschön für diejenigen die sich die mühe 
machen zu helfen :-)

von bko (Gast)


Lesenswert?

Welches EEPROM? (Atmel,Ti,ST,...)
Welches FPGA/CPLD?
Was sagt die Simulation?
Wo ist der Rest vom Code?

von Richard (Gast)


Lesenswert?

Hier der gesamte Code des Schreib/Lese Moduls ....Vom CAN-Controller 
wird gelesen und ins RAM geschrieben und vom RAM kommen die Daten ins 
EEPROM
....das ganze soll erstmal in der Smulation funktionen und erst dann 
wird es auf auf realer Hardware realisiert...

Die Sumulation des RAM Moduls und des Writestorage Moduls alleine 
funktioniert ....jedoch im Gesamtpaket dann nicht mehr

Die Daten kommen zwar erfolgreich vom Can über SPI zum RAM aber vom RAM 
nicht mehr raus bzw. nur die Daten aus der letzten Addresse werden 
gelesen und damit stehen dann im EEPROM auf jeder Adresse die selben 
Daten.

entity WriteStorage is
    Generic ( AddrWidth   : integer := 8;
              Byte        : integer := 8;
              EEPROMSize  : integer := 8192);
    Port ( Reset_n_i      : IN  STD_LOGIC;
           Clk_i          : IN  STD_LOGIC;
           DataRAM_i      : IN  STD_LOGIC_VECTOR(Byte-1 downto 0);
           DataSPI_i      : IN  STD_LOGIC_VECTOR(Byte-1 downto 0);
           ControlR_o     : out Std_logic_Vector(Byte-1 downto 0);
           CommandE_o     : OUT STD_LOGIC_VECTOR(3 downto 0);
           CommandR_o     : OUT STD_LOGIC_VECTOR(3 downto 0);
           AddressRAM_o   : OUT STD_LOGIC_VECTOR(AddrWidth-1 downto 0);
           DataEEPROM_o   : OUT STD_LOGIC_VECTOR(Byte-1 downto 0);
           DataRAM_o      : OUT STD_LOGIC_VECTOR(Byte-1 downto 0);
           WriteEnable_o  : OUT STD_LOGIC;
       --SPI- Done-Signals:
           AddrWrDone_i   : in std_logic;
           AddrRdDone_i   : in std_logic;
           DataWrDone_i   : in std_logic;
           DataRdDone_i   : in std_logic);
end WriteStorage;

architecture rtl of WriteStorage is

  type states is 
(stCAN2RAM,stCAN2RAM_Addr,stCAN2RAM_Data,stRAM2EEPROM,stRAM2EEPROM_Addr, 
stRAM2EEPROM_Data);  -- stRead = Read from the CAN controller | stWrite 
= Write from RAM to EEPROM
  signal state         : states;
  signal CountAddress   : unsigned(Byte-1 downto 0);         --Count 
Addresss
  signal count         : unsigned(3 downto 0);

begin
 SeqProc:  process(Reset_n_i, Clk_i)
   begin
    if(Reset_n_i = '0') then
      AddressRAM_o  <= (others => '0');
      DataRAM_o     <= (others => '0');
      DataEEPROM_o  <= (others => '0');
      WriteEnable_o <= '0';
      CountAddress  <= (others => '0');
      count         <= (others => '0');
      ControlR_o    <= (others => '0');
      CommandE_o    <= "0000";
      CommandR_o    <= "0000";
      state         <= stCAN2RAM;
    elsif rising_edge(Clk_i) then
      case state is
    ---------------------------READ from 
CAN--------------------------------------------------------------------- 
-------------------
        when stCAN2RAM =>
          CommandR_o    <= read_c; -- SPI-Command --> read
          CommandE_o    <="0000";
          WriteEnable_o <= '1';
          ControlR_o    <= "11110000";
          state         <= stCAN2RAM_Addr;
          CountAddress  <= (others =>'0');
          count         <= (others =>'0');


        when stCAN2RAM_Addr =>
          if(AddrRdDone_i = '1') then
            state <= stCAN2RAM_Data;
          else
            AddressRAM_o <= std_logic_vector(CountAddress);
          end if;


        when stCAN2RAM_Data =>
          if (DataRdDone_i = '1') then
            if(CountAddress ="11111111") then
                state     <= stRAM2EEPROM;
            else
              CountAddress <= CountAddress +1;
              state <=stCAN2RAM_Addr;
           end if;
         else
            DataRAM_o <= DataSPI_i;
          end if;

      -------------------------------WRITE from RAM to 
EEPROM------------------------------------------------------------------ 
-----------

        when stRAM2EEPROM =>
          CommandE_o     <= write_c;    -- SPI -Command -->Write
          CommandR_o    <= "0000";
          ControlR_o    <= "00000000";
          Writeenable_o <= '0';
          state         <= stRAM2EEPROM_Addr;
          CountAddress  <= (others =>'0');
          count         <= (others =>'0');

        when stRAM2EEPROM_Addr =>
          if(AddrWrDone_i = '1') then
            state        <= stRAM2EEPROM_Data;
          else
            DataEEPROM_o <= std_logic_vector(CountAddress);
          end if;


        when stRAM2EEPROM_Data =>
          if(DataWrDone_i= '1') then
            if(CountAddress ="11111111") then
                state <= stCAN2RAM;
            else
                CountAddress <= CountAddress+1;
                state <= stRAM2EEPROM_Addr;
              end if;
            else

            DataEEPROM_o  <= DataRAM_i;
          end if;


        when others =>
          AddressRAM_o  <= (others => '0');
          DataRAM_o     <= (others => '0');
          DataEEPROM_o  <= (others => '0');
          WriteEnable_o <= '0';
          CountAddress  <= (others => '0');
          ControlR_o    <= (others => '0');
          CommandE_o    <= "0000";
          CommandR_o    <= "0000";
          State         <= stCAN2RAM;
      end case;
    end if;
  end process;
 end rtl;

von Fpgakuechle K. (Gast)


Lesenswert?

Richard schrieb:
> if(Reset_n_i = '0')then
>       Data_o <= (others => '0');          -- Reset Data output
>       ram <= (others => (others =>'0'));  -- Reset RAM

ich bezweifle, das das synthetisierbar ist.

MfG,

von Richard (Gast)


Lesenswert?

Geanu das Gegenteil ist der Fall ...so ist es synthetisierbar.

LG,

von Christian R. (supachris)


Lesenswert?

Soso, naja, dann kann aber kein BRAM verwendet werden, sondern der 
komplette RAM wird aus einzelnen FlipFlops bzw. LUTs zusammen gebaut.

von Karl Könner (Gast)


Lesenswert?

>Soso, naja, dann kann aber kein BRAM verwendet werden, sondern der
>komplette RAM wird aus einzelnen FlipFlops bzw. LUTs zusammen gebaut.

Ja, es gibt meines Wissens keinen RAM der sich auf ein einzelnes Signal 
hin
komplett auf "0" setzen lässt. RAM muss wordweise addressiert werden.

mit einzelnen FF geht das, schon bei LUT#s habe ich meine Zweifel, 
blockweises Löschen von Flash wäre auch noch ne Idee, aber das würde 
auch nur einen Block ( i.e. 512 byte) betreffen und nicht den gesamten 
memory.

Schon bei distributed RAM aus LUTs hätte ich meine Zweifel (check mal 
mit datenblatt). Schau doch mal in den synthesereport, vielleicht hat ja 
die Synthese oder der mapper das array komplett ignoriert? Auf jeden 
fall sollte man die zeile mit "others ... others ..." im reset 
weglassen. Initialisiere es doch bei der Deklaration.

MfG

von Planer (Gast)


Lesenswert?

Wo ist die Simulation hierzu?

von Karl Könner (Gast)


Lesenswert?

Du zählst zwar die addressen hoch, aus deinem Code ist aber nicht 
erkenntlich ob die writeleitung zum RAM (WriteEnable_i) auch auf '0' 
gezogen wird.

MfG,

von John D. (Firma: Privat) (doejohn)


Lesenswert?

Hallo Richard,

habe mir den Code mal angeschaut, den Fehler aber ohne mir das Design 
mal zu skizzieren nicht auf gefunden, was daran liegt das der Code - 
sorry - nicht sehr hardwarenah geschrieben ist. Hier meine 2 Cent.

- Datenpfade & Controlpfade strikt getrennt halten!
Eine Zuweisung wie "DataRAM_o <= DataSPI_i" hat in einer FSM nichts zu 
suchen. Wenn man Datenpfade schalten will (multiplexen), dann einen 
Multiplexer verwenden und das Kontrolsignal von der FSM generieren 
lassen. Soweit ich das in deinem Code sehe wird DataRam_o immer von 
DataSPI_i getrieben, also raus damit aus der FSM. Inbesondere nicht in 
einer If-Else Anweisung innerhalb eines geclockten Prozesses, das kann 
dir "versteckte" Register generieren.

- Gleiches gilt fur AddressRam_o. Soweit ich das sehe wird der Adressbus 
nur von einem Counter getrieben. Also:

prcoess(clk)
begin
  if rising_edge(clk) then
    if Counter_Reset = '1' then
      Counter <= (others=>'0');
    elsif Counter_Increment = 1' then
      Counter <= Counter + '1';
    end if;
end process;

AddressRam_o <= Counter;

Die Signale Counter_Reset und Counter_Increment werden über die 
Kontroll-FSM gesteuert.

- Vorsicht mit 1-Process FSMs. Die kann man zwar verwenden, sollte sich 
aber bewusst sein, dass die generierten Kontrolsignale einen Takt nach 
dem State erst gültig sind. Ist nicht falsch, aber macht es 
komplizierter das Verhalten im Kopf nachzuvollziehen. Sauberer - und 
meiner Erfahrung nach - einfacher zu lesen sind 2-Prozess FSMs. Ein 
synchroner Prozess für die State-Register, in denen der aktuelle State 
gespeichert wird. Und ein asynchroner der den nächsten State berechnet 
und die Outputs entsprechend treibt.

FSM-States : process(clk)
begin
  if rising_edge(clk) then
    if Reset = '1' then
      State <= Initial_State;
    else
      State <= Next_State;
    end if;
end process;

FSM-Logic : process(State, Start_FSM, Input_A, Input_B)
begin
  -- default assignments --
  Next-State <= State;
  Output_A   <= '0';
  Output_B   <= '0';

  -- state transitions --
  case State is
    when S_IDLE =>
      if Start_FSM = '1' then
        Next_State <= S_Drive_A;
      end if;

    when S_Drive_A =>
      Next_State <= S_Drive_B;
      Output_A <= '1';

   when S_Drive_B =>
      Next_State <= S_IDLE;
      Output_B <= '1';

   when others =>
     null;

 end case;
end process;

Diese Schreibweise hat mehrere Vorteile:

1) Der Output entspricht immer genau dem State in dem man gerade ist und 
kommt genau in diesem Taktzyklus. Bei einer 1-Prozess FSM muss das nicht 
der Fall sein (wie in deinem, in dem sich die Signalzuweisung innerhalb 
des If rising_edge(clk) Statements befindet).

2) Durch die Default Assignments sind alle Signale zu jedem Zeitpunkt 
sauber definiert und es entsehen keine "versteckten" Register.

Abschließend noch 3 Anmerkungen:

- Vergiss asynchrone Reset, die hat man Anfang 2000 bei FPGAs beerdigt. 
Mit steigender Logikdichte und Geschwindigkeit machen die mehr Probleme 
als dass sie Nutzen bringen. Detailiert kann man das im Xilinx 
WhitePaper WP272 nachlesen.

- Dein Code zur Synthese des RAM ist korrekt, jeder Syntheizer sollte 
das erkennen, manche könnten sich aber an dem Reset verschlucken. Reset 
an einem RAM existiert so auch nicht, im schlimsten Fall, wie schon 
andere zuvor angemerkt haben, wird das RAM in FFs implementiert. Reset 
an einem RAM braucht man aber auch nicht, es ist völlig egal was da drin 
steht, da man in ein RAM überlicherweise erstmal reinschreibt, bevor man 
rausliest. Falls man vorinitialisierte RAMS braucht, dann macht man das 
über spezielle Init Direktiven.

- Digital Design ist kein Software Design. VHDL und Verilog sind 
Beschreibungssprachen, die beschreiben Systeme, die im Falle von FPGAs 
aus bestimmten diskreten Elementen bestehen (LUTs, FF, RAMs, Hardcores, 
DSPs). Und Synthesizer sind dumm! Alles was die versuchen ist zu 
erkennen, wie man die Beschreibung auf diese diskreten Elemente abbilden 
kann. Je klarer man seinen Code schreibt (und sich an gewisse Regeln 
hält) desto eher tut der Synthesizer das was er tun soll. Am besten geht 
das mit einem Blatt Papier und einem Stift. Man skizziert erstmal das 
Design oder einen Teil davon, hält Daten- und Kontrolpfade strikt 
getrennt und schreibt es dann genau so in VHDL/Verilog runter.

Viel Erfolg,
  JD

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.