Forum: FPGA, VHDL & Co. Pin als In oder Out konfigurieren, abhängig von einzelnem B


von Tobias P. (hubertus)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@ 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: for i in 0 to 7 generate
4
  my_port(i) <= my_data(0) when my_ddr(i)='1' else 'Z';
5
end generate;
6
7
-- Datenausgang ohne Richtungssteuerung, Open Drain Ausgang
8
-- wie PCF8574
9
10
l_label: for i in 0 to 7 generate
11
  my_port(i) <= '0' when my_data(i)='0' else 'Z';
12
end generate;

>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

von Tobias P. (hubertus)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@ 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

von Tobias P. (hubertus)


Lesenswert?

Push Pull Ausgänge? Schon gehört, weiss aber nicht genau was es ist.

von Karl (Gast)


Lesenswert?

Push-Pull ist sozusagen das "normale", mit einem Transistor gegen Vdd 
und einem gegen Masse.

von Falk B. (falk)


Lesenswert?


von Tobias P. (hubertus)


Lesenswert?

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 ...

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?


von Falk B. (falk)


Lesenswert?

@ 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
   if falling_edge(wr) then
4
      if cs='0' and sig1='0' and sig2='0' then
5
         my_sig <= '1';
6
      end if;
7
   end if;
8
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:

Was soll das denn werden? Ich bin sicher, dass man nicht auf zwei 
Flanken reagieren muss.

MFG
Falk

von Jan M. (mueschel)


Lesenswert?

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).

von Falk B. (falk)


Lesenswert?

@ 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

von Tobias P. (hubertus)


Lesenswert?

@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.

von Falk B. (falk)


Lesenswert?

@ 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

von Tobias P. (hubertus)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

@ 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

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.