Hallo,
ich bin am Experimentieren mit VHDL. Nun wollte ich einen simplen
Peripheriebaustein machen, der ein paar paralelle I/Os hat und einen
Datenbus, um ihn mit einem MC zu verbinden.
Dazu habe ich Mehrere Register definiert: einmal ein Datenregister pro
Port, und dann noch ein Richtungsregister. Die einzelnen Register sind
über einen Adressbus- und Datenbus auswähl-, beschreib- und lesbar.
Das ganze funktioniert mehr oder weniger: Schreibt man in das
Datenregister, erscheinen die Daten auch am gewünschten Port. Umgekehrt
kann man natürlich den geschriebenen Wert zurücklesen. Nun möchte ich
aber noch das Richtungsregister mit einbeziehen: Steht an irgend einer
Stelle des 8 Bit breiten Registers eine 1, ist das entsprechende Bit des
zugehörigen Ausgangsports immer auf Z, unabhängig davon, was im
Datenregister steht.
Beispiel:
Datenregoster = 11110000
Richtungsregister = 00000000 (ganzer Port ist Ausgang)
Signale an den Pins = 11110000 (Signale werden 1:1 ausgegeben)
Datenregiser = 11110000
Richtungsregister = 11100000 (erste 3 Bit Eingang, rest Ausgang)
Signale an den Pins = ZZZ10000
Nun ist die Frage, wie man das macht. Ich könnte natürlich jedes
einzelne Bit der entsprechenden Signale abfragen und "von Hand" den Pin
auf Z oder 1 oder 0 setzen. Wie könnte man es einfacher lösen?
Noch genialer wäre es, wenn jeder Pin ein Open Drain wäre, und einfach
per internen Pullup nach VCCIO gezogen würde (Altera Cyclone II FPGAs
haben ja zuschaltbare Pullups). Wie könnte man die Pins als Open Drain
konfigurieren? Und wie schaltet man die "weak pullup resistors" ein?
Ich verwende Quartus II 7.2. Der Code soll später in einem Cyclone II
EP2C8 laufen (wenn mein Board mal fertig ist, was noch etwas dauert. Bis
dann begnüge ich mich mit dem Simulator...)
Ideen?
Grüsse
Tobias
@ Tobias Plüss (hubertus)
>kann man natürlich den geschriebenen Wert zurücklesen. Nun möchte ich>aber noch das Richtungsregister mit einbeziehen: Steht an irgend einer>Stelle des 8 Bit breiten Registers eine 1, ist das entsprechende Bit des>zugehörigen Ausgangsports immer auf Z, unabhängig davon, was im>Datenregister steht.>Nun ist die Frage, wie man das macht. Ich könnte natürlich jedes>einzelne Bit der entsprechenden Signale abfragen und "von Hand" den Pin>auf Z oder 1 oder 0 setzen. Wie könnte man es einfacher lösen?
Mit einer Schleife.
1
-- Datenumschaltung per Registerbits, Push Pull Ausgang
2
3
l_label:foriin0to7generate
4
my_port(i)<=my_data(0)whenmy_ddr(i)='1'else'Z';
5
endgenerate;
6
7
-- Datenausgang ohne Richtungssteuerung, Open Drain Ausgang
8
-- wie PCF8574
9
10
l_label:foriin0to7generate
11
my_port(i)<='0'whenmy_data(i)='0'else'Z';
12
endgenerate;
>Noch genialer wäre es, wenn jeder Pin ein Open Drain wäre, und einfach
Warum? Open Drain liefert kaum Strom bei HIGH. Kann man aber machen.
>konfigurieren? Und wie schaltet man die "weak pullup resistors" ein?
Kann man in den Tools zuweisen. Kenn mich bei Altera nicht so aus.
MFG
Falk
Hallo Falk,
danke. Warum ich Open Drain verwenden wollte: Das wäre insofern ideal,
weil man dann nämlich folgendes tun kann: Wenn man bei einem Port
abwechslungsweise Daten ausgeben und wieder einlesen will muss man
normalerweise immer die Richtung vorher umschalten. So aber könnte man
einfach die Port-Daten auf 11111111 setzen. Der Ausgang wäre dann
hochohmig und würde auf VCCIO gezogen und von dem Gerät, das an den Pins
angeschlossen ist dann auf GND oder wieder VCCIO. So hätte man dan
IO-Ports ähnlich wie beim 8051, wo man ja auch 11111111 auf den Port
schreibt, um ihn als Eingang zu konfigurieren.
@ Tobias Plüss (hubertus)
>IO-Ports ähnlich wie beim 8051, wo man ja auch 11111111 auf den Port>schreibt, um ihn als Eingang zu konfigurieren.
Igitt, wer will denn sowas? Das ist ein Relikt aus längst vergangener
Zeit. Nimm Push Pull Ausgänge.
MFG
Falk
Danke für die Info.
Hey Falk, das weisst du sicher auch:
Ich möchte in einem D-FF ein bestimmtes Bit speichern, und zwar wenn 2
Signale auf Low sind. Das Bit soll sowohl übernommen werden, wenn an CS
low liegt und an WR eine fallende Flanke auftritt, als auch wenn WR auf
low ist und an CS eine fallende Flanke anliegt. Also immer auf die
jeweils spätere fallende Flanke. Natürlich könnte ich sowas machen:
signal s : std_logic;
s <= cs or wr;
process(s)
begin
if falling_edge(s) then
...
end if;
end process;
dann habe ich aber einen "gated clock", was man ja nicht tun soll. Gibts
eine Möglichkeit, das Problem zu umgehen? so gehts nicht:
if falling_edge(cs) or falling_edge(wr) then ...
@ Tobias Plüss (hubertus)
>Ich möchte in einem D-FF ein bestimmtes Bit speichern, und zwar wenn 2>Signale auf Low sind. Das Bit soll sowohl übernommen werden, wenn an CS>low liegt und an WR eine fallende Flanke auftritt, als auch wenn WR auf>low ist und an CS eine fallende Flanke anliegt. Also immer auf die>jeweils spätere fallende Flanke. Natürlich könnte ich sowas machen:
Das geht so nicht. Du musst dich schon entscheiden, welches Signal als
Takt/Strobe verwendet werden soll.
1
process(wr)
2
begin
3
iffalling_edge(wr)then
4
ifcs='0'andsig1='0'andsig2='0'then
5
my_sig<='1';
6
endif;
7
endif;
8
endprocess;
>dann habe ich aber einen "gated clock", was man ja nicht tun soll. Gibts>eine Möglichkeit, das Problem zu umgehen? so gehts nicht:
Was soll das denn werden? Ich bin sicher, dass man nicht auf zwei
Flanken reagieren muss.
MFG
Falk
Sowohl WR als auch CS scheinen keine "richtigen" Clock-Signale zu sein.
Deswegen solltest du besser ein FF mit der normalen Clock betreiben und
dir aus beiden Signalen ein Clockenable generieren:
if rising_edge(CLK) then
if (WR = 0 and last_WR=1) or (CS = 0 and last_CS = 1) then
...
last_WR / last_CS ist dann jeweils das um einen Takt verzögerte Signal
WR / CS (einfach durch ein FF geleitet).
@ Jan M. (mueschel)
>Sowohl WR als auch CS scheinen keine "richtigen" Clock-Signale zu sein.
Sind es auch nicht, es sind Strobesignale.
>Deswegen solltest du besser ein FF mit der normalen Clock betreiben und>dir aus beiden Signalen ein Clockenable generieren:
Kann man machen, kann aber bisweilen kniffelig und aufwändig werden.
Normalerweise reicht es, WR ODER CS als Takt für Scheiboperationen zu
verwenden. Damit kann man jeden uC anschliessen.
MFG
Falk
@Falk:
> Was soll das denn werden? Ich bin sicher, dass man nicht auf zwei> Flanken reagieren muss.
Eigentlich muss man ja auch nicht auf 2 Flanken reagieren. Aber in
Datenblättern von Flash oder RAM-Bausteinen beispielsweise steht oft
"Data is latched on the falling edge of WE or CE, whichever happens
first" und solche Sachen. Genau solches Timingverhalten möchte ich auch
für meinen eigenen Peripheriebaustein haben.
@ Tobias Plüss (hubertus)
>"Data is latched on the falling edge of WE or CE, whichever happens>first" und solche Sachen. Genau solches Timingverhalten möchte ich auch>für meinen eigenen Peripheriebaustein haben.
Vergiss es. Sowas ist nicht sinnvoll und in CPLDs/FPGAs nur schwer
umsetzbar. Das ist nur eine Erbe der alten asynchronen uC Busse.
Entscheide dich für ein Signal.
MFG
Falk
Okay. Im Artikel "VHDL Flankenerkennung" stand allerdings, dass man
falling_edge() und rising_edge() nur für Clock-Signale benutzen
darf/soll. Funktioniert es denn überhaupt, wenn ich ein "gewöhnliches"
Signal als Clock benutze? Oder muss ich das tatsächlich irgendwie
umbauen, dass ich mit Clock Enables arbeite?
@ Tobias Plüss (hubertus)
>darf/soll. Funktioniert es denn überhaupt, wenn ich ein "gewöhnliches">Signal als Clock benutze?
Ja.
> Oder muss ich das tatsächlich irgendwie> umbauen, dass ich mit Clock Enables arbeite?
Nein.
MFg
Falk