www.mikrocontroller.net

Forum: FPGA, VHDL & Co. CRC-Berechnung - Benötige Hilfe bei der Fehlerfindung


Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Liebe Mikrocontroller.net-Leser

Ich schreibe im Moment für einen CPLD eine SPI-GPIO-Erweiterung.
Da die Daten die über den SPI-Bus übertragen werden sehr wichtig sind 
wird eine CRC Checksumme über die gesendeten Daten gebildet und 
ebenfalls über den SPI-Bus übertragen.
Das Format der Übertragung sieht folgendermaßen aus:
Telegramm 1
Checksumme über Telegramm 1
Telegramm 2
Checksumme über Telegramm 2

Da der Mikrocontroller (Master) lediglich ein 8 Bit breiten TX-Buffer 
für das SPI-Modul besitzt ist die Aufteilung in 4 Übertragungen a 8 Bit 
notwendig.

Ich habe als Generatorpolynom folgendes ausgewählt:
x^8+x^4+x^3+x^2+1 (==> somit ist die Checksumme ebenfalls 8 Bit breit)

Ich habe mir das ganze mal manuell durchgerechnet. Als verwendetes 
Testdatenmuster habe ich 0xA3 (0b10100011) verwendet:

1010 0011 0000 0000 : 1 0001 1101
1000 1110 1
0010 1101 100
  10 0011 101
  00 1110 0010 0
     1000 1110 1
     0110 1100 10
      100 0111 01
      010 1011 110
       10 0011 101
       00 1000 0110

Somit habe ich als Rest 0x86.
Auf der Seite http://zorc.breitbandkatze.de/crc.html habe ich das ganze 
verifizieren wollen.
Da komme ich aber auf folgende Werte:
Eingestellte Parameter: CRC-Order: 8  /  CRC-Polynom: 1D  /  Initialwert 
FF  /  Final XOR value:00    Reverse Data Bytes 0    Final XOR value 0
Result: 8A

Eingestellte Parameter: CRC-Order: 8  /  CRC-Polynom: 1D  /  Initialwert 
FF  /  Final XOR value:00    Reverse Data Bytes 0    Final XOR value 1
Result: 51

Eingestellte Parameter: CRC-Order: 8  /  CRC-Polynom: 1D  /  Initialwert 
FF  /  Final XOR value:00    Reverse Data Bytes 1    Final XOR value 0
Result: B9

Eingestellte Parameter: CRC-Order: 8  /  CRC-Polynom: 1D  /  Initialwert 
FF  /  Final XOR value:00    Reverse Data Bytes 1    Final XOR value 1
Result: 9D

Meine Testbench liefert mir als Ergebnis 0x42.


Als Testbench habe ich folgenden Code:
                                       -- Testbench
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;


-- Leere entity
entity mein_DUT_tb is
generic (
    gDatenlaenge  : integer :=8;
  gCRCLaenge    : integer :=8);

end entity mein_DUT_tb ;
 
architecture Verhalten of mein_DUT_tb is

 -- Moduldeklaration
COMPONENT  crc 
port (
  data_in  : in std_logic_vector (gDatenlaenge - 1 downto 0);
    crc_en   : in std_logic;
  rst    : in std_logic;
  clk    : in std_logic;
    crc_out : out std_logic_vector (gCRCLaenge - 1 downto 0));
end component;

signal    data_in  :  std_logic_vector (gDatenlaenge - 1 downto 0):= (others =>'0');  
signal    crc_en   :  std_logic  :='0';
signal    rst    :  std_logic  :='0';
signal    clk    :  std_logic  :='0';
signal    crc_out  :  std_logic_vector (gCRCLaenge - 1 downto 0):= (others =>'0');  

procedure Testdaten_anlegen 
(
signal crc_en  : out  std_logic;
signal rst    : out  std_logic
) is
  
begin
  --wait until rising_edge(clk);
  crc_en<= '1';
  wait until rising_edge(clk);
  wait until rising_edge(clk);
  crc_en<= '0';
  rst<='1';
  wait until rising_edge(clk);
  rst<='0';
  wait until rising_edge(clk);
  
end Testdaten_anlegen ;
--0000010110001100


begin
  clk   <= not clk  after 20 ns;  -- 25 MHz Taktfrequenz
  

  

  
 CRC_berechnen: process 
  begin  
      rst <= '1';
    wait until rising_edge(clk);
      rst <= '0';
    wait until rising_edge(clk);
  
    
  data_in <= conv_std_logic_vector((163),gDatenlaenge);  Testdaten_anlegen (crc_en => crc_en, rst => rst);  
  

  for I in 0 to 255 loop
    data_in <= conv_std_logic_vector((I),gDatenlaenge);  Testdaten_anlegen (crc_en => crc_en, rst => rst);
    end loop;
    
 wait until rising_edge(clk);
  crc_en<= '1';
  wait until rising_edge(clk);
  crc_en<= '0';
  wait until rising_edge(clk);
 
  
  
end process;

 
  -- Modulinstatziierung
  mein_dut : crc
  port map (
   data_in    =>    data_in,
  crc_en     =>    crc_en,
  rst      =>    rst,
  clk      =>    clk,
  crc_out    =>    crc_out            
  );
         
end architecture;

Als DUT habe ich folgenden generierten Code von 
http://outputlogic.com/?page_id=321 eingefügt
-------------------------------------------------------------------------------
-- Link zum Generieren des Files: http://outputlogic.com/?page_id=321
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Ports
-- data_in    : Paralleler Eingang der Daten
-- crc_en    : Startsignal
-- rst      : Reset
-- clk      : CLK-Signal
-- crc_out    : Paralleler Ausgang an dem die berechnete CRC bereitgestellt wird


-------------------------------------------------------------------------------
-- Copyright (C) 2009 OutputLogic.com
-- This source file may be used and distributed without restriction
-- provided that this copyright statement is not removed from the file
-- and that any derivative work contains the original copyright notice
-- and the associated disclaimer.
-- 
-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-------------------------------------------------------------------------------
-- CRC module for data(7:0)
--   lfsr(7:0)=1+x^2+x^3+x^4+x^8;
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity crc is
  port ( data_in : in std_logic_vector (7 downto 0);
    crc_en , rst, clk : in std_logic;
    crc_out : out std_logic_vector (7 downto 0));
end crc;

architecture imp_crc of crc is
  signal lfsr_q: std_logic_vector (7 downto 0);
  signal lfsr_c: std_logic_vector (7 downto 0);
begin
    crc_out <= lfsr_q;

    lfsr_c(0) <= lfsr_q(0) xor lfsr_q(4) xor lfsr_q(5) xor lfsr_q(6) xor data_in(0) xor data_in(4) xor data_in(5) xor data_in(6);
    lfsr_c(1) <= lfsr_q(1) xor lfsr_q(5) xor lfsr_q(6) xor lfsr_q(7) xor data_in(1) xor data_in(5) xor data_in(6) xor data_in(7);
    lfsr_c(2) <= lfsr_q(0) xor lfsr_q(2) xor lfsr_q(4) xor lfsr_q(5) xor lfsr_q(7) xor data_in(0) xor data_in(2) xor data_in(4) xor data_in(5) xor data_in(7);
    lfsr_c(3) <= lfsr_q(0) xor lfsr_q(1) xor lfsr_q(3) xor lfsr_q(4) xor data_in(0) xor data_in(1) xor data_in(3) xor data_in(4);
    lfsr_c(4) <= lfsr_q(0) xor lfsr_q(1) xor lfsr_q(2) xor lfsr_q(6) xor data_in(0) xor data_in(1) xor data_in(2) xor data_in(6);
    lfsr_c(5) <= lfsr_q(1) xor lfsr_q(2) xor lfsr_q(3) xor lfsr_q(7) xor data_in(1) xor data_in(2) xor data_in(3) xor data_in(7);
    lfsr_c(6) <= lfsr_q(2) xor lfsr_q(3) xor lfsr_q(4) xor data_in(2) xor data_in(3) xor data_in(4);
    lfsr_c(7) <= lfsr_q(3) xor lfsr_q(4) xor lfsr_q(5) xor data_in(3) xor data_in(4) xor data_in(5);


    process (clk,rst) begin
      if (rst = '1') then
        lfsr_q <= b"11111111";
      elsif (clk'EVENT and clk = '1') then
        if (crc_en = '1') then
          lfsr_q <= lfsr_c;
        end if;
      end if;
    end process;
end architecture imp_crc; 



Wenn mir da vielleicht jemand einen Tipp geben kann wo der Fehler liegt 
wäre ich sehr dankbar.

Viele Grüße

Martin

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen

Hat keiner eine Idee?

VG

Martin

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Leute müssen erst wach werden ^^

Autor: René D. (Firma: www.dossmatik.de) (dose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>
>     process (clk,rst) begin
>       if (rst = '1') then
>         lfsr_q <= b"11111111";
>       elsif (clk'EVENT and clk = '1') then
>         if (crc_en = '1') then
>           lfsr_q <= lfsr_c;
>         end if;
>       end if;
>     end process;
> end architecture imp_crc;
>
> [/vhdl]
>

Das CRC Thema ist sehr groß.
CRC beschreibt den Vorgang. Unterschiede gibt es noch in den Startwerten 
und wie der CRC Wert übertragen wird.

Ich habe mich mit CRC32 für Ethernet beschäftigt. hier wird der CRCWert 
negiert übertragen.
Der Startzustand der Register sind 1.
Das ist bereits die Erste mathematische Optimierung. Dadurch werden die 
ersten einlaufend Bits des Datenstromes negiert.
Für dein CRC muss du mehr wissen oder du kannst mit einem CRC-Generator 
kleine Datenström berechnen. Günstig ist hier ein Byte und die 
dazugehörige Checksumme.


Versuchen mal den Resetzustand auf ... zu ändern.

   lfsr_q <= b"00000000";

Autor: Martin R. (herki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rene

Vielen Dank für Deine Antwort.

Ich habe den Resetzustand wie Du vorgeschlagen hast geändert.
Resultat:
Die simulierten Ergebnisse entsprechen meiner manuellen Rechnung. :)

Leider komme ich bei der Berechnung mit dem CRC-Rechner 
(http://zorc.breitbandkatze.de/crc.html) aber auf andere Ergebnisse.

Hast Du mit dem Rechner Erfahrung?
Ich habe folgende Werte eingegeben:
Startwert 0
CRC-Order 8
CRC-Polynom 1D

Wenn mir da vielleicht noch jemand unter die Arme greifen kann wäre mein 
Tag gerettet.

Viele Grüße

Martin

Autor: Elizar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei einem SPI verwendet man in der Regel keinen CRC, denn es kann ja 
keine Fehler geben. Es ist alles auf einer Leiterplatte, EMV Probleme 
hat man keine. Es gibt keine Kabel durch irgendwelche Umgebungen.
Falls man doch EMV Probleme hat sollte man die loesen. Nicht mit einem 
CRC, sondern mit einem richtigen Design. Und auf ein Kabel gehoert SPI 
auch nicht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.