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: 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
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
Push Pull Ausgänge? Schon gehört, weiss aber nicht genau was es ist.
Push-Pull ist sozusagen das "normale", mit einem Transistor gegen Vdd und einem gegen Masse.
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 | 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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.