Forum: FPGA, VHDL & Co. FPGA mit Datenbus eines MCs verbinden


von Wolfgang (Gast)


Lesenswert?

Hallo Jungens,
ich möchte folgendes machen:
auf einem Mikrocontrollerboard mit einem LPC2xxx Controller (Weiss noch 
nicht genau welchen ich verwenden möchte) soll ein FPGA mit drauf, der 
als Peripheriebaustein funktioniert.
Nach aussen wird der FPGA viele SPI-Schnittstellen haben, und mehrere 
PWM-Kanäle.
Das ansich ist auch nicht das PRoblem, sondern das folgende:
der FPGA soll beim Mikrocontroller am externen Memory Interface 
angeschlossen werden, sodass er vom Controller wie ein SRAM angesprochen 
werden kann (memory mapped I/O).

Könnt ihr mir vielleicht einen Tipp geben, wie ich die Register im FPGA 
realisieren kann und den Daten-/Adressbus, damit der Mikrocontroller 
damit zurechtkommt? Ich bin noch nicht so der Profi auf VHDL, aber ich 
will das jetzt lernen. Schematic ist nicht so dolle für solche Sachen 
;-)

Gruss Wolfgang

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Könnt ihr mir vielleicht einen Tipp geben, wie ich die Register im FPGA
> realisieren kann und den Daten-/Adressbus, damit der Mikrocontroller
> damit zurechtkommt?
Am einfachsten dürfte hier die Verwendung eines Dual-Ported-RAM sein. So 
kannst du die beiden Taktdomänen uC <-> FPGA am einfachsten entkoppeln.

> Ich bin noch nicht so der Profi auf VHDL, aber ich will das jetzt lernen.
Dann solltest du aber vorerst die Aufgabe in einzelne kleine Häppchen 
aufteilen. Mach erst mal das asynchrone Interface zum uC mit LEDs und 
Tastern. Dann machst du dir Gedanken, wie du das Ganze auf den FPGA-Takt 
einsynchronisierst und verarbeitest.

von Wolfgang (Gast)


Lesenswert?

Hi Lothar,
Wie beschreibt man denn ein solches dual port RAM in VHDL?
Ich will übrigens Quartus II von Altera verwenden, falls das eine Rolle 
spielt.

> Dann solltest du aber vorerst die Aufgabe in einzelne kleine Häppchen
> aufteilen. Mach erst mal das asynchrone Interface zum uC mit LEDs und
> Tastern. Dann machst du dir Gedanken, wie du das Ganze auf den FPGA-Takt
> einsynchronisierst und verarbeitest.

so ähnlich dachte ich mir das schon. Am besten wäre wohl ein dual port 
RAM, auf der einen seite Taster, um den uC zu simulieren, auf der 
anderen LEDs um die einzelnen Bits im RAM zu sehen. Oder?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Wie beschreibt man denn ein solches dual port RAM in VHDL?
> ...Quartus II von Altera verwenden, falls das eine Rolle spielt.
Tut es durchaus...
Wie ein DPRAM beschrieben wird, damit fertige RAM-Bausteine verwendet 
werden, ist z.B. für Xilinx im Synthesis Guide XST.pdf beschrieben. Für 
Altera dürfte es sowas ähnliches auch geben.

von gonzo (Gast)


Lesenswert?

Wie wäre es als Alternative, wenn Du den Takt für Dein FPGA aus dem Takt 
des µC beziehst? Da die Bussignale des µC höchstwahrscheinlich synchron 
zu seinem Takt sind, kannst Du Dir das Einsynchronisieren dann sparen. 
Intern kann das FPGA mit einem ganzzahligen Vielfachen des so 
vorgegebenen Takts arbeiten, wenn Du diesen schnelleren Takt per PLL aus 
dem externen Takt ableitest. Dann brauchst Du auch hier nichts zu 
synchronisieren...

von Wolfgang (Gast)


Lesenswert?

Hi gonzo,
das Problem dabei ist, dass mein uC einen Quarzoszillator von 4 MHz hat 
und den Takt dann intern auf 72 MHz vervielfacht. Leider lässt sich 
diese vielfache Frequenz nirgends ausgeben, ich hätte hächstens 4 MHz 
zur Verfügung...

von RAMZUGREIFER (Gast)


Lesenswert?

Hallo,

ich mach das mit einem LPC2294 Controller.
Ist eigentlich ganz einfach, der LPC2294 hat ein
externes Memory-Interface und an einem Pin
kannst du den internen Takt ausgeben lassen,
der nennt sich XCLK.
Mit diesem Takte ich dann das FPGA Interface
synchron zum LPC Daten-Adressbus.

Du brauchst eigentlich nur den Datenbus,
den Adressbus, das WE (BLS Signal beim LPC2294)
und das CS.
Im LPC mußt du die Register entsprechen setzen,
und dann kannst du auf das FGPA mittels eines
Memory-Befehls lesend und schreibend zugreifen.
Den VHDL Code für das Interface ist eigentlich
auch kein Hexenwerk.


Gruß

Ralf

von Wolfgang (Gast)


Lesenswert?

Hi Ralf,
kannst du mir mal ein bisschen von deinem VHDL-Code zeigen?
Wie übernimmst du die Daten?
Ich hab intern ein Signal definiert:

signal data : std_logic_vector(7 downto 0);

und dann

process begin
  wait until rising_edge(clk);
  if we = '0' and ce = '0' and oe = '1' then
    data <= datenbus;
  end if;
  if we = '1' and ce = '0' and oe = '0' then
    datenbus <= data;
  end if;
end process;

wobei datenbus dann die 8 pins sind für 8 parallele Bits.

von RAMZUGREIFER (Gast)


Lesenswert?

>Hi Ralf,
>kannst du mir mal ein bisschen von deinem VHDL-Code zeigen?

Aber nur weil du es bist ;-).
Ich habe zwei prozesse. Einen für Register lesen
und einen für Register schreiben.

clk      ist xclk vom LPC2294
cs       ist cs(1) vom LPC2294
we       ist bls(0) vom LPC2294
address  ist der Datenbus vom LPC2294
datenbus ist der 8 bit breite Datenbus vom LPC2294
rst      ist eine Resetsignal, kannst du aber auch weglassen
1
  signal data : std_logic_vector(7 downto 0);
2
3
  process (clk, rst)          -- register schreiben
4
  begin
5
    if (rst = RESET_ACTIVE) then
6
       -- init something
7
    elsif rising_edge(clk) then
8
      if (cs = '0' and we = '0') then
9
        case address is
10
           when x"00" =>     -- x"00" entspricht ADR x80000000 am LPC2294
11
             data <= datenbus;
12
13
          when others =>
14
            null;
15
        end case;
16
      end if;
17
    end if;
18
  end process;
19
20
21
  process (clk, rst)           -- register lesen
22
  begin
23
    if (rst = RESET_ACTIVE) then
24
      -- init something
25
    elsif rising_edge(clk) then
26
      if (cs = '0' and we = '1') then
27
        case address is
28
          when x"00" =>    -- x"00" entspricht ADR x80000000 am LPC2294
29
           datenbus <= data;
30
31
         when others =>
32
            null;
33
        end case;
34
      end if;
35
    end if;
36
  end process;


Mehr verrate ich nicht. Den Rest mußt du schon
selbst rausfinden. Die größte Herausforderung besteht
jetzt noch darin im LPC die Register entsprechend zu
setzen.

Gruß

Ralf

von RAMZUGREIFER (Gast)


Lesenswert?

Ups, ich habe noch vergessen:

Im Toplevelfile teile ich
den Datenbus in Data_in
und Data_out auf, und
setze den Datenbus hochohmig
wenn oe = 0 und cs = 0 ist.
1
  signal data : std_logic_vector(7 downto 0);
2
3
  process (clk, rst)          -- register schreiben
4
  begin
5
    if (rst = RESET_ACTIVE) then
6
       -- init something
7
    elsif rising_edge(clk) then
8
      if (cs = '0' and we = '0') then
9
        case address is
10
           when x"00" =>     -- x"00" entspricht ADR x80000000 am LPC2294
11
             data <= data_in;
12
13
          when others =>
14
            null;
15
        end case;
16
      end if;
17
    end if;
18
  end process;
19
20
21
  process (clk, rst)           -- register lesen
22
  begin
23
    if (rst = RESET_ACTIVE) then
24
      -- init something
25
    elsif rising_edge(clk) then
26
      if (cs = '0' and we = '1') then
27
        case address is
28
          when x"00" =>    -- x"00" entspricht ADR x80000000 am LPC2294
29
           data_out <= data;
30
31
         when others =>
32
            null;
33
        end case;
34
      end if;
35
    end if;
36
  end process;
37
38
39
  -- Zuweisung Datenbus
40
  data    <= data_out when (oe = '0' and cs = '0') else (others => 'Z');
41
  data_in <= data;


Gruß

Ralf

von Wolfgang (Gast)


Lesenswert?

Hallo,
> Aber nur weil du es bist ;-).

cool, vielen Dank :-)

Noch ne kleine Frage.
Und zwar habe ich am FPGA auch noch ein EA DOGM128 Grafikdisplay dran, 
welches über SPI angesprochen wird. Im FPGA ist dann ein 1 kByte grosser 
Puffer, welcher das anzuzeigende Bild beinhaltet! Der FPGA gibt diesen 
Puffer über SPI dann periodisch an das Display aus.
Jetzt möchte ich eine kleine hardwaremässige Grafikunterstützung 
realisieren: schreibt der Controller in ein spezielles Command Register 
einen Opcode, z.B. für "zeichne eine Linie", dann soll der FPGA in 
diesen 1k grossen Puffer selbständig die entsprechende Linie malen. Geht 
sowas, was mir da vorschwebt?

von gonzo (Gast)


Lesenswert?

Gehen es natürlich tut, aber kompliziert es wird. Ich mir das nicht 
antun würde... ;-)

Aber wie wäre es mit folgender einfach zu realisierender Optimierung: Da 
Du das RAM im FPGA sehr flexibel aufteilen kannst, könntest Du es dem 
Prozessor in einem zusätzlichen Adressbereich bitweise adressierbar 
präsentieren. Dann kannst Du ein Pixel durch eine einfache 
Schreiboperation setzen und sparst Dir ein Lesen und ein Odern.

Die nächste Stufe wären dann Operationen auf rechteckigen Pixelblöcken 
im FPGA (Clear, Move, Copy etc.). Das sollte auch noch einfach zu 
realisieren sein. Ob es sich aber auch lohnt, mußt Du wissen. Ich würde 
das ganz am Ende der Entwicklung angehen.

Falls Du Einfluß auf die Hardware nehmen kannst: Lege XCLK unbedingt auf 
einen Clock-Eingang des FPGA. Nur dann kannst Du die PLL-Lösung von oben 
implementieren.

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.