mikrocontroller.net

Forum: FPGA, VHDL & Co. i2c slave controller


Autor: tobias oddoy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich weiss, dass dieses Thema schon in einem Thread behandelt wurde, aber
die Lösungen waren etwas unbefriedigend für mich, da für mich zu
kompliziertes Interface .
Ich versuche einen einfachen i2c Slave controller für ein fpga zu
programmieren. Dieser soll eigentlich nur dazu dienen Bytes zu
empfangen. Auf Opencores gibt es zwar einen I2C Master
controller, aber der nützt mir recht wenig, da halt Master Controller
und nicht Slave.


Das interface stelle ich mir so vor:
generic :
   i2c_slave_adress
port :
sys_clock  : in
scl_in     : in
sda_in     : in

Data_ready       : out              -- Daten vorhanden
Data_read_clock  : in               -- Lesetakt für daten
Data_read        : in               -- Lesen ausführen
Data             : out              -- Payload

Den ganzen std_logic Kram habe ich mal weggelassen. Hat jemand schon
mal sowas gemacht (evtl. CPLD als Porterweiterung) das auch
funktioniert hat.

Den IP-Core will ich später mal benutzen, um mir debug informationen
von meinem Cypress EZ-USB expansion modul zu holen, da der Hersteller
blöderweise vergessen hat die RXD und TXD Leitungen zu verdraten. Somit
habe ich keinen Zugang zur UART auf dem USB Controller, was sich beim
debuggen echt dämlich macht.

Danke an jeden, der dazu etwas schreiben kann oder zur Hilfe beiträgt.
Schon fertiger VHDL Code ist natürlich sehr willkommen. :D, bitte kein

freakiger Verilog Code, ich möchte das auch in etwa verstehen können
was da passiert, wenn ich Anpassungen am Interface vornehmen muss.

G. Tobias

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, hier unten. In der Simulation (zusammen mit dem Master von
Opencores) funktioniert alles einwandfrei. Ich übernehme aber keine
Haftung - war zu schnell reingehackt. Hoffe, Du blickst da durch, wenn
nicht, dann frag', ich versuche mich zu erinnern ;-)

Kest


  library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use IEEE.STD_LOGIC_UNSIGNED.all;
--
------------------------------------------------------------------------ 
-

    entity i2c_core_slave is
        port (
            clk        : in    std_logic;
            nReset     : in    std_logic;
            Dout       : out   std_logic_vector(7 downto 0);
            data_valid : out   std_logic;
            SCL        : in    std_logic;
            SDA        : inout std_logic
            );
    end entity i2c_core_slave;
--
------------------------------------------------------------------------ 
-
    architecture behav of i2c_core_slave is

        type   states is (s_idle, s_start, s_read_a, s_ack);
        signal state, next_state : states;

        signal oSCL, oSDA                          : std_logic
          := '0';
        signal SDAt, SCLb                          : std_logic;
        signal sda_pad_o, sda_pad_i, sda_padoen_oe : std_logic;
        signal rx_reg                              : std_logic_vector(7
downto 0);
        signal rx_done                             : std_logic;
        signal int_reg                             : std_logic_vector(7
downto 0);
        signal stop_sy                             : std_logic
          := '0';
        signal count                               : std_logic_vector(2
downto 0) := "000";
--
------------------------------------------------------------------------ 
-
    begin

       -- SDA       <= sda_pad_o when (sda_padoen_oe = '0') else
'Z';
        sda_pad_i <= SDA;
        SDAt      <= '0'       when (SDA = '0')           else
'1';
        SCLb      <= '0'       when (SCL = '0')           else
'1';

--
------------------------------------------------------------------------ 
-
-- Statemachine für i2c-Bus (slave)
--
------------------------------------------------------------------------ 
-
        process (nReset, clk)--, state, SDA, stop_sy, count)
        begin
            if nReset = '0' then
                rx_done       <= '0';
                sda_pad_o     <= '0';
                sda_padoen_oe <= '0';
                data_valid    <= '0';
                next_state    <= s_idle;
                int_reg       <= (others => 'Z');
                Dout          <= (others => 'Z');
            elsif clk'event and clk='1' then


                case state is
                    when s_idle =>
                        data_valid <= '0';
                        rx_done       <= '0';
                        sda_padoen_oe <= '0';

                        if SDA = '0' then
                           -- sda_padoen_oe <= '0';
                            next_state    <= s_start;
                        else
                            next_state <= s_idle;
                           -- sda_padoen_oe <= '0';

                        end if;

                    when s_start =>
                        data_valid    <= '0';
                        rx_done       <= '0';
                        sda_padoen_oe <= '1';

                        if stop_sy = '0' then
                            next_state <= s_read_a;
                        else
                            next_state <= s_idle;
                        end if;

                    when s_read_a =>    -- hier SDA übernehmen und
schiften
                        data_valid <= '0';
                        rx_done       <= '0';


                        if (count = "000" and stop_sy='0') then
                            next_state <= s_ack;
                        else
                            next_state <= s_read_a;
                        end if;

                    when s_ack => -- acknowledge senden (SDA auf 0)
                        data_valid    <= '1';
                        rx_done       <= '1';

                        sda_pad_o     <= '0';
                        sda_padoen_oe <= '0';
                        int_reg       <= rx_reg;
                        Dout          <= rx_reg;
                        next_state    <= s_start;  -- idle
                end case;
            end if;
        end process;

--
------------------------------------------------------------------------ 
-
-- stop erkennen, (a)synchron
--
------------------------------------------------------------------------ 
-
        process (nReset, clk)--, SCLb, SDAt, state, oSDA)
        begin
            if nReset = '0' then
                stop_sy <= '0';
                oSDA    <= '1';
                elsif clk'event and clk='1' then

                if state = s_idle then
                    stop_sy <= '0';
                end if;

                if (oSDA = '0' and SDAt = '1') then  -- also
steigende Flanke
                    oSDA <= '1';
                    if SCLb = '1' then  -- und SCL hoch, => stop
Signal
                        stop_sy <= '1';
                    else
                        stop_sy <= '0';
                    end if;
                elsif (oSDA = '1' and SDAt = '0') then  --
vorsichtshalber auch die fallende erkennen
                    oSDA <= '0';
                end if;
            end if;
        end process;

--
------------------------------------------------------------------------ 
-
-- states weiterschalten
-- auf die fallende SCL-Flanke triggern
-- wenn genug CLKs vorhanden, kann man auch SCL als CLK nehmen, erstmal
aber nicht
--
--
------------------------------------------------------------------------ 
-
        process (clk, nReset,     state, stop_sy, oSCL, SCLb, rx_done)
        begin
            if nReset = '0' then
                state  <= s_idle;
                oSCL   <= '1';
                count  <= "000";
                rx_reg <= (others => 'Z');
            elsif (clk'event and clk = '1') then  -- Register

                if stop_sy = '1' then
                    state <= s_idle;
                end if;

                if state = s_idle then
                    count <= "000";
                end if;

                if (oSCL = '1' and SCLb = '0' ) then  -- fallende
Flanke? -- and stop_sy='0'
                    state <= next_state;                -- nächster
Zustand
                    oSCL  <= '0';       -- aktuellen Wert merken
                elsif (oSCL = '0' and SCLb = '1') then  --
steigende Flanke?
                    if (state = s_idle) or (state = s_ack) then  --
Zähler reseten
                        count <= "000";
                    else
                        if rx_done = '0' then
                            rx_reg <= rx_reg(6 downto 0) & SDAt;  --
shiften
                            count  <= count+"001";      -- 8 Bits
abzählen
                        end if;
                    end if;
                    oSCL <= '1';
                end if;
            end if;
        end process;
--
------------------------------------------------------------------------ 
-
    end architecture behav;

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Kest

was ist mit der Slave-Adresse, kann man die einstellen ?

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
am Ausgang hast Du einfach die Daten, die ankommen. (Serial auf
Parallel), das war's auch schon. Wenn die richtige Adresse angekommen
ist, dann... tja, ist alles rudimentär, ich weis ;-) Aber immerhin :-)

Kest

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also mehr ein "Sniffer", ein Slave müsste ja mit seinem
Acknowledge entsprechend reagieren, abhängig davon, ob
er angesprochen wurde oder nicht.

Besteht allgemeines Interesse an einem Slave in VHDL, der sowohl
beschrieben als auch gelesen werden kann und frei
adressierbar ist + im Sniffer-Mode arbeiten kann ?

Habe gerade ein Projekt, wo sich sowas ganz gut machen
würde, aber ich bräuchte ein paar Tester, die sich den
Code anschauen und simulieren + Bug-Reports liefern.

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
WAs dazu kommt ist einfach mal eine kleine (wirklich sehr kleine)
Statemachine, die läuft eben los, wenn die Adresse erkannt wird. Ich
wollte sie blos nicht jetzt aus einem Projekt rausreißen, weil man
durcheinander kommt...

Aber Sniffer ist ja schon fast zu 90% ein I2C slave ;-)

Kommt, Leute, macht doch auch was :-)
Übrigens, ein Tipp, diese "kleine" Statemachine, ist bei Opencores,
bei dem I2C Master mitdabei (da wird irgendwie ein Mixrocontroller
emuliert oder so... etwas suchen müsst ihr schon ;-))

Kest

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also der Multimaster bei Opencores hat mir nicht so
gefallen, war auch ganz schön umfangreich...
Teile des Slaves habe ich schon fertig, wie gesagt,
man kann auch von dem Slave lesen und nach jedem
Transfer gibts einen Status, also z.B. TX_UNDERRUN,
RX_OVERFLOW, NO_ACK ...
Aber einfach so zum kopieren und abheften gibts den nich :-)))

Autor: tobias oddoy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interesse an einem i2c Slave Controller würde ich dann mal anmelden, am
besten mit Richtungsumschaltung, damit man den auch ins FPGA packen
kann, bzw. einen IO Buffer für die FPGA Pins benutzen kann.

sprich
sda_in   : in
sda_out  : out
sda_read : out -- wenn '1',dann sda_in lesen wenn '0' dann sda out
schreiben.

verdrahtung im fpga top level würde dann so aussehen
IOBUF port map (O => sda_in,
               IO => FPGA_pin_sda,
                I => sda_out;
                T => sda_read
              );
Würde mich als Tester und zur Evaluierung anbieten, da ich das sowieso
brauchen werde, bzw. das zum laufen kriegen muss.

Gruß Tobias

Autor: John-Eric (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo
würde mich auch dafür interressieren.
wüsste bloß nicht wie ich das mit dem ack hinbekommen sollte.
da ich mich auch bloß privat damit beschäfftige.
wäre warscheinlich ganz hilfreich zum verständnis.
das i2c protokoll habe ich mir schon angeschaut und auch verstanden.
hätte auch nicht das problem mit zu versuchen den zu erstellen.
kann mich nur weiter bringen.
bin schon super glücklich das meine selbstprogrammierte funkuhr super
läuft. die musste ich ja schließlich ganze 4mal umprogrammieren
(grins)
erst alles asynchron, dann hier das forum gefunden und dan musste ich
das noch alles synchron schreiben.
das forum hier hat mir schon sehr geholfen.
mfg

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens, das Code, was ich oben gepostet habe, ist schon mehr als ein
Sniffer - ACK bekommt man jeweils nach jedem empfangenen Byte zurück
(ist mir gerade eingefallen ;-))

Ich bin der Meinung, dass solche kleine Sachen man selber reinhacken
kann. Dabei lernt man sehr schnell dazu - bzw. welche Fehler dann
auftauchen. Klar, wenn man nur fertigen SAchen nimmt, ist schon
praktisch, aber na ja... jedem das seine. Für mich wäre sowas
interessant, wenn man einfach alles anschaut, wie das andere gemacht
haben.

Ich, für mein Teil, optimiere nur selten - programmiert, getestet,
synthetisiser, getestet, geändert, synthetisiert, getestet - okay. Wenn
da irgendwelche Latches sind oder so, beachte ich nicht. Nur, wenn ich
dann Zeit habe - das ist aber oft nicht der Fall :-/
Ich gucke also sehr gerne mal die Sachen von Dir an, FPGA_User :-)

Kest

Kest

Autor: high_speed (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fremden Code zu lesen ist meist nicht sehr einfach.
Da ist es meist viel einfacher es selber zu schreiben.
Ich habe erst einmal den Code von Kest ein bisschen aufgeräumt.

Hier jetzt ein paar Tipps um die Lesbarkeit des Codes zu verbessern:

1. Bei der Signaldeklaration für jedes Signal oder zum mindestens für
gleiche Signale eine Zeile verwenden.
2. Bei Signalen, die nicht auf die Verwendung schließen lassen, noch
einen Kommentar anfügen.

Eine Vereinfachung habe ich auch noch gefunden:
Neu:   stop_sy <= SCLb;     -- und SCL hoch, => stop Signal

Alt:  if SCLb = '1' then
         stop_sy <= '1';
      else
         stop_sy <= '0';
      end if;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
---------------------------------------------------------------------------

entity i2c_core_slave is
   port (
         clk          : in    std_logic;
         nReset       : in    std_logic;
         Dout         : out   std_logic_vector(7 downto 0);
         data_valid   : out   std_logic;
         SCL          : in    std_logic;
         SDA          : inout std_logic
        );
end entity i2c_core_slave;

---------------------------------------------------------------------------

architecture behav of i2c_core_slave is

   type   states is (s_idle, s_start, s_read_a, s_ack);
   signal state, next_state : states;

   signal oSCL              : std_logic  := '0';  
   signal oSDA              : std_logic  := '0'; 
   signal SCLb              : std_logic;
   signal SDAt              : std_logic;

   signal sda_pad_i         : std_logic;
   signal sda_pad_o         : std_logic;
   signal sda_padoen_oe     : std_logic;

   signal rx_reg            : std_logic_vector(7 downto 0);
   signal rx_done           : std_logic;
   signal int_reg           : std_logic_vector(7 downto 0);
   signal stop_sy           : std_logic := '0';
   signal count             : std_logic_vector(2 downto 0) := "000";

---------------------------------------------------------------------------
  
begin

   -- SDA        <= sda_pad_o when (sda_padoen_oe = '0') else 'Z';
   sda_pad_i  <= SDA;
   SDAt       <= '0'       when (SDA = '0')           else '1';
   SCLb       <= '0'       when (SCL = '0')           else '1';

---------------------------------------------------------------------------
-- Statemachine für i2c-Bus (slave)
---------------------------------------------------------------------------

   process (nReset, clk)  --, state, SDA, stop_sy, count)
   begin
      if nReset = '0' then
         rx_done       <= '0';
         sda_pad_o     <= '0';
         sda_padoen_oe <= '0';
         data_valid    <= '0';
         next_state    <= s_idle;
         int_reg       <= (others => 'Z');
         Dout          <= (others => 'Z');
      elsif clk'event and clk='1' then

         case state is

         when s_idle =>
            data_valid    <= '0';
            rx_done       <= '0';
            sda_padoen_oe <= '0';                        
                                   
            if SDA = '0' then
               -- sda_padoen_oe <= '0';
               next_state    <= s_start;
            else
               next_state <= s_idle;
               -- sda_padoen_oe <= '0';                  
            end if;

         when s_start =>
            data_valid    <= '0';
            rx_done       <= '0';
            sda_padoen_oe <= '1';

            if stop_sy = '0' then
               next_state <= s_read_a;
            else
               next_state <= s_idle;
            end if;

         when s_read_a =>         -- hier SDA übernehmen und schiften
            data_valid  <= '0';
            rx_done     <= '0';                        

            if (count = "000" and stop_sy='0') then 
               next_state <= s_ack;
            else
               next_state <= s_read_a;
            end if;

         when s_ack =>            -- acknowledge senden (SDA auf 0)
            data_valid    <= '1';
            rx_done       <= '1';                        
            sda_pad_o     <= '0';
            sda_padoen_oe <= '0';
            int_reg       <= rx_reg;
            Dout          <= rx_reg;
            next_state    <= s_start;  -- idle

         end case;

      end if;

   end process;

---------------------------------------------------------------------------
-- stop erkennen, (a)synchron
---------------------------------------------------------------------------

   process (nReset, clk)
   begin
      if nReset = '0' then
         stop_sy <= '0';
         oSDA    <= '1';
      elsif clk'event and clk='1' then
 
         if state = s_idle then
            stop_sy <= '0';                      --??? Reihenfolge
         end if;

         if (oSDA = '0' and SDAt = '1') then     -- also steigende
Flanke
            oSDA    <= '1';
            stop_sy <= SCLb;                     -- und SCL hoch, =>
stop Signal
         elsif (oSDA = '1' and SDAt = '0') then  -- vorsichtshalber
auch die fallende erkennen
            oSDA    <= '0';
         end if;
      end if;
   end process;

---------------------------------------------------------------------------
-- states weiterschalten
-- auf die fallende SCL-Flanke triggern
-- wenn genug CLKs vorhanden, kann man auch SCL als CLK nehmen, erstmal
aber nicht
---------------------------------------------------------------------------

   process (clk, nReset)
   begin
      if nReset = '0' then
         state  <= s_idle;
         oSCL   <= '1';
         count  <= "000";
         rx_reg <= (others => 'Z');
      elsif (clk'event and clk = '1') then    -- Register

         if stop_sy = '1' then
            state <= s_idle;
         end if;

         if state = s_idle then
            count <= "000";
         end if;

         if (oSCL = '1' and SCLb = '0' ) then    -- fallende
Flanke? -- and stop_sy='0'
            state <= next_state;                 -- nächster Zustand
            oSCL  <= '0';                        -- aktuellen Wert
merken
         elsif (oSCL = '0' and SCLb = '1') then  -- steigende
Flanke?
            if (state = s_idle) or (state = s_ack) then  -- Zähler
reseten
                count <= "000";
            else
               if rx_done = '0' then
                  rx_reg <= rx_reg(6 downto 0) & SDAt;  -- shiften
                  count  <= count+"001";         -- 8 Bits abzählen
               end if;
            end if;
            oSCL <= '1';
         end if;
      end if;
   end process;

---------------------------------------------------------------------------

end architecture behav;

MfG
Holger

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Tobias

welchen Vorteil siehst Du in der Auftrennung von SDA in SDA_in
und SDA_out ? Die FPGA-Pins sind doch bidirektional, die
Synthese erkennt automatisch, wie der Input-Buffer und der
Output-Tristate-Buffer an den Core angeschlossen werden müssen.
von außen kommen ja auch nur 2 Leitungen, SDA und SCL.

Egal, werde bis Freitag mal den Slave-Core präsentieren,
geplant ist TX und RX doppelt gepuffert, also man kann schon
das nächste Byte einschreiben während das vorherige über I2C
rausgeht, FIFOs sollten sich ohne große Kopfstände anschließen
lassen (in der 1 Version evt. noch nicht), es soll keine
FPGA-spezifischen Elemente geben, Transfer bricht ab, wenn
kein ACK vom Master kommt (bei Read vom Slave).

Autor: Kest (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Auftrennung finde ich nicht mal so dumm :-o

Ich kann nur aus Erfahrung sagen, dass bidirektionale Pins oft stress
machen (sogar auch in der Simulation). Da sind dann plötzlich
kurzschlüsse oder was weis ich. Hab mal was gemacht, und dann mit dem
Opencores-Core von i2c getestet und es klapte nicht (in der
Simulation). In der Hardware hat man dann entsprechend Pulldown/Up
Widerstände und da hat es schon funktioniert. Na ja... wir nähern uns
langsam dem Wishbone ;-))

Kest

Autor: tobias oddoy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast ja recht mit den Bidirektionalen Pins, habe halt festgestellt, wenn
man so eine Auftrennung vornimmt, lassen sich leichter Fehler erkennen,
weil man besser erkennen kann, woher die Signale kommen. Ansonsten
sieht man bei der Simulation nur ein 'X' und man weiss nicht, woher
der Kurzschluss kommt. Außerdem muss man ja nicht die Hersteller
Synthese Bibliotheken verwenden, sondern kann den IO Buffer auch "per
hand" erstellen und ist dann völlig plattformunabhängig.
Hauptsache es funktioniert

process .......
  if T = '1' then
      IO <= 'Z';
      O  <= IO ;
  else
      I  <= O;
      O  <= IO;
  end if;
end process;

Übrigens Danke für deine Hilfe !

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
meinen Slave habe ich in der Codesammlung abgelegt,
SDA ist erstmal nicht aufgetrennt,
hab versucht, alles so verständlich wie möglich zu schreiben,
für den einen oder anderen sind bestimmt ein paar neue
VHDL-Features zu entdecken.
bitte mal damit rumspielen, wer Zeit hat.

Autor: Andreas Müller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Jungs,

ich hab mir mal das I2C Projekt auf Opencore angeschaut und find es
recht kompliziert. Hat jemand ein besseres Projekt was er mir mal geben
kann? Hab versucht es komplett mit Automaten zu realisieren und
irgendwie ist da noch der Wurm drin. Wäre euch echt dankbar.

Autor: anfänger in vhdl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was bedeutet oder was beschreiben genau die signale sda-pad-i und sda 
pad-o und sda-padoen-oe und int-reg

Autor: Tommy Tacker (tommy776)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm,immer noch niemand geantwortet! :(

aber mal eine andere frage:
wenn ich register des sensors auslese (register 0x0C bis 0x0F),die im 
default-zustand mit werten belegt sind, dann steht nach dem senden des 
repeated-start und der anschließenden Registeradresse sowie den 4 oben 
genannten adressen immer ein ACK.das sehe ich auf dem oszi.
wenn ich nun die achsenregister auslese fehlt das ACK nach dem 
repeated-start(+sensoradresse) und nach dem lesen des jeweiligen 
LOW-byte der x-bzw. y-achse!
im avr-studio steht aber im statusregister nach 0x10 (steht für repeated 
start) als nächstes der status (0x40) -> slave has been transmitted,ACK 
has been received!

kann das sein?????

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.