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
> 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.
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?
> 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.
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...
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...
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
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.
>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
signaldata:std_logic_vector(7downto0);
2
3
process(clk,rst)-- register schreiben
4
begin
5
if(rst=RESET_ACTIVE)then
6
-- init something
7
elsifrising_edge(clk)then
8
if(cs='0'andwe='0')then
9
caseaddressis
10
whenx"00"=>-- x"00" entspricht ADR x80000000 am LPC2294
11
data<=datenbus;
12
13
whenothers=>
14
null;
15
endcase;
16
endif;
17
endif;
18
endprocess;
19
20
21
process(clk,rst)-- register lesen
22
begin
23
if(rst=RESET_ACTIVE)then
24
-- init something
25
elsifrising_edge(clk)then
26
if(cs='0'andwe='1')then
27
caseaddressis
28
whenx"00"=>-- x"00" entspricht ADR x80000000 am LPC2294
29
datenbus<=data;
30
31
whenothers=>
32
null;
33
endcase;
34
endif;
35
endif;
36
endprocess;
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
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
signaldata:std_logic_vector(7downto0);
2
3
process(clk,rst)-- register schreiben
4
begin
5
if(rst=RESET_ACTIVE)then
6
-- init something
7
elsifrising_edge(clk)then
8
if(cs='0'andwe='0')then
9
caseaddressis
10
whenx"00"=>-- x"00" entspricht ADR x80000000 am LPC2294
11
data<=data_in;
12
13
whenothers=>
14
null;
15
endcase;
16
endif;
17
endif;
18
endprocess;
19
20
21
process(clk,rst)-- register lesen
22
begin
23
if(rst=RESET_ACTIVE)then
24
-- init something
25
elsifrising_edge(clk)then
26
if(cs='0'andwe='1')then
27
caseaddressis
28
whenx"00"=>-- x"00" entspricht ADR x80000000 am LPC2294
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?
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.