Forum: FPGA, VHDL & Co. Adresslatch für AVR in CPLD fehlerhaft?


von A. N. (netbandit)


Lesenswert?

Hallo,

ich habe folgendes vor:
Ich möchte einen Speicher über einen CPLD an einen ATMega128 
anschließen. irgendwann soll dann in den CPLD XC95144XL noch was anderes 
hinein. Dazu benötige ich das Durchschleifen aller Leitungen vom AVR zum 
SRAM durch den CPLD.

Nun arbeite ich gerade daran grundlegend das Speicherinterface im CPLD 
hinzubekommen. Da der SRAM recht groß ist, habe ich eine entsprechende 
Bankumschaltung integriert. Leider macht mir das Adresslatch etwas 
probleme.
1
-- Adresslatch
2
LATCH : process(RESET, ALE_AVR)
3
begin
4
  if RESET = '0' then
5
  
6
    S_A_SRAM(7 downto 0) <= (others => '0'); 
7
  elsif falling_edge(ALE_AVR) then
8
9
    S_A_SRAM(7 downto 0) <= AD_AVR;
10
  end if;
11
end process;

Bei der fallenden Flanke soll hier das untere Adressbyte übernommen 
werden. Leider übernimmt er ab und zu auch schon teilweise das 
Datenbyte, welches vom AVR gleich nach dem Abschalten des ALE Signales 
auf die AD Leitungen gelegt wird. Der CPLD schafft es also nicht 
rechtzeitig alle Adressbits zu speichern.

Was kann ich hier tun?
Ich habe es bei 4MHz, 8MHz und 16 MHz AVR-Frequenz ausprobiert. Wenn ich 
ca. 100pF vom ALE-Eingang am CPLD zu GND lege, dann tritt je nach 
Zimmertemperatur sogar eine langanhaltende Besserung ein (Jedoch am 
nächsten Tag läuft es wieder nicht).

Jetzt noch ein paar Randdaten:
- der CPLD läuft mit 3,3V und ist vom Typ 10ns
- der AVR läuft mit 5V und ich habe es bei verschiedenen Frequenzen 
ausprobiert
- Die Kabel der AD-Leitungen und ALE-Leitung sind ca. 10cm lang.
(von einer Testplatine zur nächsten)

Hat jemand vielleicht schon einmal ein Adresslatch im CPLD integriert 
und ähnliche Probleme gelöst?

Vielen dank im Voraus,
Netbandit

von Volker (Gast)


Lesenswert?

mir ist nur eins aufgefallen,
Du hast kein Latch sondern ein flankengesteuertes FF gebaut.


Gruß

Volker

von Banause (Gast)


Lesenswert?

Das FF ist flankengesteuert, sollte aber trotzdem funktionieren.
Mich deucht, dass der ATmega recht anspruchsvoll an dieser Stelle ist, 
da gibt es n+1 Bits, die richtig gesetzt werden müssen. Atmel schreibt 
da einige bemerkenswerte Sätze im Manual.

von A. N. (netbandit)


Lesenswert?

Ja stimmt, aber auch pegelgesteuert gibt es das gleiche Problem :)

Ich bin etwas voran gekommen und hab eine kleine FSM programmiert, 
welche das untere Adressbyte immer 4 Zyklen nachdem ALE auf 1 gegangen 
ist, einmalig speichert (und erst wieder wenn ALE zwischenzeitig auf 0 
gegangen war).

Bis jetzt läuft es auf 8 MHz vom AVR recht gut, den Takt im CPLD brauch 
ich eh später, es kostet mich eben zusätzlich noch einmal 2 Register und 
irgendwie kommt mir soetwas leicht Überzogen für solch eine Anwendung
vor.

Vielleicht hat ja jemand noch eine andere Idee...
1
LATCH : process(ALE_AVR, CLK)
2
begin
3
4
  if ALE_AVR = '0' then
5
6
    Z_LATCH <= "00";
7
  elsif falling_edge(CLK) then
8
9
    case Z_LATCH is
10
11
      when "11" => 
12
      
13
        S_A_SRAM(7 downto 0) <= AD_AVR;
14
        Z_LATCH <= "11";
15
     when others =>
16
17
        Z_LATCH <= Z_LATCH + 1;
18
   end case;
19
  end if;  
20
end process LATCH;

@Banause:

Stimmt schon, der AVR scheint etwas anspruchsvoll zu sein, was sein 
Latch angeht. Im Datenblatt steht leider nur, dass der dem Latch ca. 5ns 
zum Speichern gibt, nachdem ALE auf 0 gegangen ist. das ist schon recht 
wenig.  Leider habe ich keine Funktion in den Registern gefunden mit der 
man hier ein besseres Timing einstellen kann, es gibt da eben nur die 
Wate States und über die kann man das ALE Signal nicht beeinflussen.

Also im Datenblatt hab ich dazu noch nichts gefunden oder meinst du ein 
anderes Dokument?

von Banause (Gast)


Lesenswert?

Ich meine das dicke Manual; weitere Dokumentation dazu kenne ich erst 
mal nicht. Wie hast du das Bit XMBK gesetzt (external memory bus 
keeper)? Das kann Schwierigkeiten im Timing machen! Mein Kollege hatte 
da mal was - ich weiß es aber nicht mehr genau und kann ihn nicht mehr 
fragen, da er ausgebüxt ist.

von A. N. (netbandit)


Lesenswert?

Das hab ich auf low, da ich denke, dass hochohmige Zustände erstmal 
nicht so verkehrt sind, wenn der AVR nichts auf dem Bus zu suchen hat.

von Banause (Gast)


Lesenswert?

Blöd, war so eine Vermutung. Dann hilft nur noch der LA weiter.

von Volker (Gast)


Lesenswert?

nun ja, 5ns ist ja wirklich nciht viel, schon mal die Flanken vom ALE
Signal auf einem Oszi angesehen?
Eventuell sind da zu starke Überschwinger drauf.

Auch noch wichtig: Bist Du mit dem ALE Signal auf einen dafür 
vorgesehenen
"global Clock" Eingang des CPLDs gegangen?

Gruß Volker

von A. N. (netbandit)


Lesenswert?

Ja einen LA hab ich nicht, ich kann jedoch das "wackeln" der unteren 
Adressbits ganz gut mit dem Oszi beobachten.
Ist die untere Adresse 0x00 und soll dann ein Byte 0xFF geschrieben 
werden, so ist es eben durchaus möglich, dass anstatt 0x00 als Adresse 
0xFF gespeichert wird.

Das ALE Signal war sowohl schon einmal auf einem normalen Pin als auch 
auf dem CLK Pin, auf dem normalen Pin lief es sogar etwas besser...
Es sind zumindest bei 16 MHz gewisse Überschwinger vorhanden, die 
bekomme ich auch nicht einem kleinen Kondensator weg. Allerdings ist es 
hier sehr fragwürdig, was das Oszi da anzeigt, denn je nachdem ob das 
Oszi dransteckt oder nicht läuft es eben besser mit dem ALE oder eben 
auch nicht. Also beeinflusst das Oszi die Signalform durchaus 
beträchtlich.

von Banause (Gast)


Lesenswert?

Da weißt du jetzt, wo der Hund begraben liegt. Ich würde mal noch 
versuchen, am XC95144 entsprechend harte timing constraints zu setzen.
Für 5 ns mit Überschwingern könnte der -10 Typ auch ein wenig zu schlaff 
sein.
Gute Besserung - Banause

von Volker (Gast)


Lesenswert?

>>Es sind zumindest bei 16 MHz gewisse Überschwinger vorhanden, die
>>bekomme ich auch nicht einem kleinen Kondensator weg.

Die Überschwinger sollten eigentlich nicht frequenzabhängig sein, da ja 
nur ein einzelner Schaltvorgang zählt.

Versuch mal in alle Leitungen (ALE, und AD) 33 Ohm in Reihe zu schalten 
und dann noch etwa 33 pF nach Masse.

Was passiert, wenn Du das Kabel mit den AD-Signalen verlängerst, das ALE
Signal aber bei 10cm belässt, damit sollte eigenlich das Timing besser 
werden.

Gruß Volker

von Volker (Gast)


Lesenswert?

Du könntest auch mal folgendes machen:

Programmier mal einen Counter/Frequenzteiler in den CPLD, der vom 
ALE-Signal als Clock gespeist wird. Damit könnte man sehen, ob auf ALE 
solche Überschwinger vorhanden sind, die die "falling Edge" mehrfach 
auslösen.

Gruß Volker

von Joerg W. (joergwolfram)


Lesenswert?

Wenn Du alle Signale "Durchschleifen" willst, dann evtl. auch den 
gemultiplexten Bus. Den mit Widerständen (470 Ohm sollte gehen) auf die 
Signale koppeln. Die XC95... haben soweit ich weiß leider keine eigenen 
Buskeeper. Bei mir hatte es zumindest so geklappt mit XMBK=0 und latchen 
der durchgeschleiften Signale.

Gruß Jörg

von A. N. (netbandit)


Lesenswert?

So, nach einigen Stunden Testzeit scheint diese Mini FSM recht gut zu 
funktionieren. Es sind nur noch sehr wenige Fehler beim Lesen/Schreiben 
am SRAM aufgetreten.
Die restlichen Fehler liegen vielleicht daran, dass die Bustreiber nach 
dem abschalten des RD/WR -Signales den Bus entsprechend hochohmig 
geschaltet haben. Hier habe ich nachdem Vorbild der Latch FSM ebenfalls 
eine kleiner Verzögerung eingebaut. Seither hatte ich keine Fehler mehr.

Da ich im Moment nicht so viel Zeit habe, werde ich es wohl erst einmal 
dabei belassen, bis ich die entsprechenden Ressourcen im CPLD vielleicht 
für was anders brauche, bis jetzt reicht es ja noch.

Im Moment müsste ich eigentlich besser für Klausuren lernen und wollte 
"nur mal eben schnell" einige Gedankenblitze in die Tat umsetzen, bevor 
ich die nächsten Wochen nur noch Taschenrechner und Zahlen sehe :)

Ich denke, dass ich in den nächsten Semesterferien ein bisschen mehr 
zeit finde der Ursache genauer auf den Grund zu gehen, dann werde ich 
Volkers Vorschläge mal umsetzen und mich deswegen noch einmal melden.

Den Vorschlag von Jörg kann ich im Moment nicht ganz nachvollziehen. Der 
gemuxte Bus wird ja in den CPLD eingebracht und dort dann in einen 
getrennten Daten und Adressbus geteilt (durch das Latch) daher wird 
dieser ja schon "durchgeschliffen". Aber vielleicht hab ich es einfach 
nur falsch verstanden, vielleicht könntest du das ganze noch einmal 
konkretisieren.

Also dann danke ich erst einmal für die Vorschläge und ich werde mich 
melden, sobald ich mich noch einmal genauer damit beschäftigt habe.

von Joerg W. (joergwolfram)


Lesenswert?

Das "Durchschleifen" wie ich es beschrieben habe, bewirkt folgendes:

Beim Schreiben auf das externe RAM liegen auf dem Datenbus an:

Adresse -> undefiniert -> Daten

wobei XMBK keinen Einfluss hat. Durch die Laufzeit im CPLD schalten die 
durchgeschleiften Signale etwas später um. Und gerade diese Zeit gewinnt 
man beim Adresslatch. Man kann die Verzögerung auch noch etwas erhöhen, 
indem man die Signale nicht direkt durchschleift, sondern z.B. mit RD 
UND-verknüpft.

Die in meinem oberen Post beschriebenen Widerstände brauchst Du nicht. 
Das war bei mir damals notwendig zwecks "Hotplugging".

Gruß Jörg

von A. N. (netbandit)


Lesenswert?

Ja das wäre schon eine Idee, wenn die geänderten Pegel auf dem AD Bus 
eben später am "Latch" ankommen, dann werden noch die Adressen richtig 
gespeichert. So wie ich das sehe, ist jedoch die einzige Möglichkeit, 
soetwas möglichst definiert zu machen mit Hilfe von Timing 
Constraints...

Da müsste ich mich erstmal genauer einarbeiten. Bis jetzt hab ich das 
Timing von der ISE erledigen lassen :-) Wie würde man so etwas 
definieren, wenn es ca. 5 bis 10ns später erst am Latch ankommen soll?

Es einfach nur durch eine Verknüpfung zu machen scheint mir da etwas 
risikoreich, je nachdem wie die ISE das ganze in den CPLD programmiert 
klappt es dann halt mal und mal nicht.

von A. F. (artur-f) Benutzerseite


Lesenswert?

Blöde Frage, aber haben die beiden eine gemeinsame Masse (CPLD <-> AVR)?

von A. N. (netbandit)


Lesenswert?

Jup, nur dass eben die 5V Betriebsspannung vom AVR zum CPLD durch einen 
weiteren Regler auf 3.3V runtergebracht wird.

von Joachim (Gast)


Lesenswert?

Das Problem mit dem ALE eines AVR in Verbindung mit einem FPGA hatte ich 
anfangs auch. Habe aber gelernt: "Erst lesen, dann machen".
Sieht man sich die Timings des AVR an, stellt man fest, dass es nicht 
einfach ist, auf die fallende Flanke von ALE zu synchronisieren, weil 
die Adresse schon 5ns danach schon "weg" ist.
Man muss erstmal nachsehen, wie lange die Adresse gemeinsam mit dem 
Signal ALE anliegt, um die Adressen korrekt zu lesen.
Die Adresse liegt vor ALE = L für 1/2tclk -5ns am AVR an.
Außerdem liegt sie mindestens 5ns nach ALE = L an. Die zusätzlichen 5ns 
bringen uns zwar nichts für die Berechnung, aber verschafft einige 
Timingsicherheit.
Bei 16MHz also 0.5*62.5ns -5 = 26.25ns.
Das sind 38.09MHz.
Um also sicher einen Takzyklus des FPGA "in das Zeitfenster 
hineinzubringen", müsste der Takt zum Sampeln theoretisch mindestens 
2.38 mal so hoch sein, wie der Takt des 16MHz-AVR. Etwas zusätzliche 
Sicherheit kann nicht schaden.
Also 40MHz würde ich mindestens nehmen. Mein Aufbau bestand aus 16MHz 
AVR und 50MHz FPGA, aber wie gesagt 40MHz tuns auch.
Eine Abtastrate doppelt so hoch die die AVR-Frequenz REICHT NICHT!!

Das Einlesen geht ganz einfach in meinem Fall
1
process (RESET, CLK)
2
begin
3
  if (RESET='0') then
4
    -- hier Reset
5
  elsif (rising_edge(CLK)) then
6
  if ALE = '1' then
7
      Global_Address(15 downto 8) <= Address;
8
      Global_Address(7 downto 0) <= ADBUS;
9
  end if;
10
  if WR = '0' then
11
            HOST_WR_DATA <= ADBUS;
12
        end if;
13
  end if;  
14
end process;

Die Information an "ADBUS" wird also immer eingelesen, solange ALE High 
ist. Dabei ist es egal, ob der FPGA-Takt 40MHz oder 200MHz ist.
Es wird eben immer solange eingelesen, bis es sich durch ALE = Low nicht 
mehr ändert. Nur die Mindesttaktrate ist wichtig, damit in den Bereich, 
wo die Adressdaten anliegen garantiert eine Abtastflanke fällt.
Eine Verwendung der (gelatchten) Adresse "Global_Address" erfolgt ja 
erst bei Auftreten von WR oder RD, weshalb "zu früh abgetastete" 
ungültige Adressdaten überhaupt keine Rolle spielen.

Bei mir funktioniert das hundertprozentig.

Joachim

von A. N. (netbandit)


Lesenswert?

Hi Joachim,

ja so hatte ich das erst auch mal getestet. Ich habe einen CLK von 66MHz 
also nach deiner Berechnung völlig ausreichend. leider hat das bei mir 
nicht funktioniert. Ich hab kein LA, um genau zu prüfen, warum das damit 
nicht immer funktioniert hat.

Ausgehend von dieser Version hab ich dann die FSM getestet, die läuft 
bei mir bei 8MHz (AVR Takt) 100%ig.
Heute Abend will ich meine Timings noch einmal überarbeiten und gucken 
ob ich wieder auf 16MHz hochschalten kann.

Ich denke ein Großteil der Probleme, die ich mir hier damit gemacht habe 
kommen durch die ca. 10cm langen Leitungen und die damit einhergehenden 
Kapazitäten. Die Signale, die ich mit dem Oszi messe sind alles anderes 
als klar und Überschwinger sind an der Tagesordnung. Eine wesentliche 
Verbesserung verspreche ich mir, wenn ich irgendwann den Testaufbau auf 
eine Platine bringe und damit die Leitungswege kürzer werden.

Vielleicht helfen hier auch kleine Tiefpässe an den Leitungen, wie 
Volker es vorgeschlagen hat.

Interessant ist halt, dass man zu diesem Problem kaum etwas im Internet 
findet, wobei ich mir vorstellen könnte, dass die Realisierung eines 
Adresslatches über PLDs und FPGAs für µCs grundsätzlich sehr verbreitet 
sein wird.

von Joachim (Gast)


Lesenswert?

Naja, wenn es natürlich Störprobleme sind, hilft es auf der 
Programmseite nicht wirklich weiter.
Als ich mal mit Xilinx-CPLDs rumgespielt hatte, machten diese anfangs 
gar nicht, was ich wollte. Die sind sehr empfindlich bezüglich 
unsauberem Aufbau, Spannungsversorgung und Masse. Erst auf einer 
"gescheiten" Platine liefen die einwandfrei. Die "Steckbrettlösung" mit 
Adapterboard war eine Katastrophe.

Jedenfalls programmtechnisch muss es so funktionieren.
Anfangs hatte ich auch eine Kombination AVR<>CPLD (Altera). Da hatte ich 
einfach einen globalen Clockeingang des CPLD an das Signal ALE 
angeschlossen.
Das war natürlich die einfachste Lösung als Anfänger.
Aber mit einem FPGA erscheint mir eine vollsynchrone Lösung besser als 
die asynchrone Lösung unter Verwendung dedizierter Clockpins. Ist 
sicherer und einfacher auf andere Hardware portierbar. Die Clockpins 
können einem schnell mal ausgehen, wenn man die allzu großzügig 
verschwendet.
Und da man RD und WR eh auf den Systemtakt synchronisieren muss, macht 
ein separater Clock durch ALE nur Probleme.

Viel Erfolg


Joachim

von H.A.R.R.Y. (Gast)


Lesenswert?

"- Die Kabel der AD-Leitungen und ALE-Leitung sind ca. 10cm lang.
(von einer Testplatine zur nächsten)"

Bei einer Hold-Zeit von 5ns kann es durch den "fliegenden" Aufbau und 
dadurch bedingte kapazitive Last durchaus vorkommen, daß das ALE erst im 
CPLD ankommt nachdem sich schon einige Adressbits geändert haben!

So etwa Knappes funktioniert üblicherweise nur mit so kurz als möglich 
gehaltenen Leiterbahnen. In der AVR-Doku steht auch noch ein Halbsatz 
zum Thema Latch vom 74AC-Typ. Einige CPLDs sind hier langsamer - okay, 
ich kenne den verwendeten CPLD-Typen nicht so gut aber eventuell liegt 
es schon daran.

Ein synchrones Design (mit extra Takt), wie von Joachim vorgeschlagen, 
würde ich an dieser Stelle lieber nicht machen, da in der AVR-Doku ja 
schon drinsteht, daß das XRAM-Interface nicht absolut präzise zum 
AVR-Takt arbeitet - die zetliche Relation kann schwanken. Und dann noch 
eine zusätzliche Taktquelle die asynchron zum AVR-Takt ist; scheint mir 
eher das Problem zu verschlimmern.

Also ist mein Vorschlag mal das Timing des CPLD (Setup- und besonders 
Hold-Zeiten der FFs) zu prüfen und nachzuschauen, ob das überhaupt 
ausreicht.

Kann es zusätzlich daran liegen, daß der AVR mit 5V läuft? Das bedingt 
am CPLD mit 3,3V einen niedrigeren Umschaltpunkt für '1'->'0' und kann 
daher nochmal etwas Hold-Zeit kosten durch die Zeit für das Abfallen des 
ALE.

Rein prinzipiell hätte ich auch ein pegelgesteuertes äquivalent zum 
74xx573 eingebaut. Das ist zwar nicht gerne gesehen (weil voll 
asynchrones Design) hier aber gerechtfertigt.

Die 5ns Nachlauf der Adresse zum ALE werden nicht aus irgendwelchen 
Takten des AVR gewonnen sondern rein durch fest eingestellte 
Laufzeitglieder und -effekte. Daher nutzt auch das Ändern der 
Taktfrequenz rein gar nichts.

Gruß H.A.R.R.Y.

von A. N. (netbandit)


Lesenswert?

Ja der fliegende Aufbau ist wirklich ein Graus. Dabei hat sowohl der AVR 
als auch der CPLD eine sehr vernünftige Spannungsversorgung mit allen 
C's die so an die VCC-Pins heran gehören. Aber die Leitungen eben...

Aber was soll man tun? So ein CPLD Design entwirft man nicht mal locker 
auf einer extra dafür gefertigten Platine. Solange der fertige VHDL Code 
nicht gefittet wurde, steht ja noch gar nicht fest an welchen Pin 
welches Signal kommt. Ab einer entsprechend hohen Belegung des CPLD (bei 
mir der Fall) kann schon das Einfügen eines kleinen logischen Gatters in 
den VHDL-Code dazu führen, dass etliche Pins umgelegt werden. Hier kann 
man wohl wirklich nur mit Testplatinen arbeiten, wo man mal eben schnell 
die Drähte zum CPLD umstecken kann.

Mein "syncronlatch" von oben geht zumindest bei 8MHz problemlos. Bei 
16MHz kommt es ab und an wieder zu Memoryproblemen, aber hier weiß ich 
noch nicht, ob das am Latch liegt oder an einer anderen Stelle meines 
Designs (hab mir diese Fehler noch nicht über ein Oszi ansehen können).

Wäre der CPLD etwas größer könnte man bestimmt ein vollsyncrones Design 
aufbauen, sobald die Signale vom CPLD erstmal richtig "eingetaktet" 
wurden würde dann alles richtig laufen... aber ich fürchte, dafür reicht 
der CPLD eben nicht :-)

von Holger (Gast)


Lesenswert?

Sehr interessant dein Projekt.

Schau dir mal diesen Thread an.
Beitrag "AVR Ethernet Platine"


#define CPLD_MM_  _attribute ((section (".cpldmm")))
#define FTDI_MM_  _attribute ((section (".ftdimm")))
#define USB_MM_   _attribute ((section (".usbmm")))

#define BANK0_  _attribute ((section (".bank0")))
#define BANK1_  _attribute ((section (".bank1")))


im Makefile müssen nun die Addressen zu den obigen Sections stehen:

LDFLAGS += -Wl,--section-start=.cpldmm=0x801100
LDFLAGS += -Wl,--section-start=.ftdimm=0x801200
LDFLAGS += -Wl,--section-start=.usbmm=0x801300
LDFLAGS += -Wl,--section-start=.bank0=0x802000
LDFLAGS += -Wl,--section-start=.bank1=0x808000

Der Addressbereich des CPLD's startet also physikalisch an Addresse
0x1100. Im Source kann nun eine Memory-gemappte Variable zu diesem
Addressbeeich definiert werden.

uint8_t CPLD[256] CPLD_MM;

Beim Zugriff auf diese 256 Char Array wird nun physikalisch in die
Addressen 0x1100 bis 0x11FF gemappt.



Anbei mal mein Memory Mapped Bank Controller zur Ansteuerung von 512Kb
SRAM und zwei beliebigen Memory Mapped Geräten. Das ganze passt in
einen XC9536XL benötigt alle 34 verfügbaren Pins und verbraucht 27
Makrozellen von den 36 verfügbaren. Da der MMB aber intern selber zwei
Register speichert und demzufolge auch die komplette Addresslogic des
AVR's benötigt kann für euer Projekt einiges eingespart werden.

entity MMB is
  port(
    AVR_AD: inout std_logic_vector(7 downto 0);
    AVR_AH: in std_logic_vector(7 downto 0);
    AVR_ALE,AVR_RD,AVR_WR: in std_logic;

-- A0-A7, A15,A16,A17,A18, CS~
    AL: out std_logic_vector(7 downto 0);
    AH: out std_logic_vector(3 downto 0);
    CS: out std_logic_vector(2 downto 0)
  );
end MMB;

-- 512Kb SRAM pinning
-- CS~     -> CPLD.CS(2)
-- WR\     -> AVR.WR\
-- RD\     -> AVR.RD\
-- A0-A7   -> CPLD.AL
-- A8-A14  -> AVR.A8-A14
-- A15-A18 -> CPLD.AH
-- IO0-IO7 -> AVR.AD0-AD7

-- AVR pinning
-- WR\     -> CPLD.AVR_WR\
-- RD\     -> CPLD.AVR_RD\
-- ALE     -> CPLD.AVR_ALE
-- AD0-AD7 -> CPLD.AVR_AD
-- A8-A15  -> CPLD.AVR_AH

-- zwei memory mapped devices
-- CPLD.CS(0) oder CPLD.CS(1)
-- 8 Bit gelatchter Addressraum an CPLD.AL, pro devices also 256 bytes 
addressraum
-- + 4 Bit Addressraum ?ber Bankswitch register 0 zus?tzlich, d.h. durch 
vorheriges
-- schreiben von 4 bits in Bank_Register_0 kann beim sp?teren Zugriff 
auf die
-- memory mapped devives ?ber CPLD.AH der addressbereich manuell auf 
12bit erweitert
-- werden. Eventuell k?nnen diese 4 bits in CPLD.AH == Bank_Register_0 
auch f?r andere
-- aufgaben benutzt werden. CPLD.AH enth?lt also je nach Addressleitung 
A15 entweder den
-- vorher gespeicherten Wert aus Bank_Register_0 oder Bank_Register_1.

-- ?ber Addressen 0x0500 - 0x05FF kann ?ber jedes Byte das interne 
Bank_Register
-- gelesen oder geschrieben werden
-- Bits 0-3 definieren A15-A18 f?r Bank 0
-- Bits 4-7 definieren A15-A18 f?r Bank 1
-- je nach Level auf A15 werden diese Bits auf CPLD.AH ausgegeben
-- greift man also auf Addressen kleiner 0x8000 zu so wird CPLD.AH == 
Bank_Register_0 sein
-- ansonsten CPLD.AH == Bank_Register_1
-- im falle das CPLD.CS(2) also aktiv ist und somit der SRAM selektiert 
wurde bestimmen die
-- Werte im Bank_Register die obersten 4 Adressbits f?r den SRAM. Da die 
Bank_Register frei
-- programmierbar sind kann im Speicherbereich von 0x0000-0x7FFF und 
0x8000 bis 0xFFFF jede
-- beliebige 32Kb SRAM Bank eingeblendet werden, auch doppelt.


architecture behavioral of MMB is

  signal Bank_Register: std_logic_vector(7 downto 0) := (others => '0');
  signal AL_Latch: std_logic_vector(7 downto 0) := (others => '0');
  signal CS_Latch: std_logic_vector(2 downto 0) := (others => '0');

  alias A15: std_logic is AVR_AH(7);
  alias Bank_0: std_logic_vector(3 downto 0) is Bank_Register(3 downto 
0);
  alias Bank_1: std_logic_vector(3 downto 0) is Bank_Register(7 downto 
4);
begin

  process(AVR_ALE, AVR_AD, AVR_AH)
  begin
    if AVR_ALE = '1' then
      AL_Latch <= AVR_AD;

-- Chip Select Addressdekodierung, low active
-- ATMega162 0x0500 start externer SRAM
-- ATMega128 0x1100 start externer SRAM

-- hier Addressdekodierung f?r ATMega162
-- Addressbereich     Typ           AVR_AH        CS~
-- 0x0500 bis 0x05FF  --- CPLD     0000 0101      111
-- 0x0600 bis 0x06FF  CS0          0000 0110      110    externes Device 
0
-- 0x0700 bis 0x07FF  CS1          0000 0111      101    externes Device 
1
-- 0x0800 bis 0xFFFF  CS2 SRAM                    011    512Kb SRAM

      CS_Latch <= "011";
      if AVR_AH(7 downto 2) = "000001" then
        case AVR_AH(1 downto 0) is
          when "01"   => CS_Latch <= "111";
          when "10"   => CS_Latch <= "110";
          when "11"   => CS_Latch <= "101";
          when others => NULL;
        end case;
      end if;
    end if;
  end process;


  process(AVR_WR, AVR_RD, AVR_AD, CS_Latch, Bank_Register)
  begin
    AVR_AD <= (others => 'Z');
    if CS_Latch = "111" then
      if AVR_WR = '0' then
        Bank_Register <= AVR_AD;
      else
        if AVR_RD = '0' then
          AVR_AD <= Bank_Register;
        end if;
      end if;
    end if;
  end process;

  AL <= AL_Latch;
  AH <= Bank_0 when A15 = '0' else Bank_1;
  CS <= CS_Latch;
end behavioral;

von Joachim (Gast)


Lesenswert?

>  process(AVR_ALE, AVR_AD, AVR_AH)
>  begin
>    if AVR_ALE = '1' then
>      AL_Latch <= AVR_AD;

von Joachim (Gast)


Lesenswert?

Sorry, falsche Taste abgefeuert :-)

>  process(AVR_ALE, AVR_AD, AVR_AH)
>  begin
>    if AVR_ALE = '1' then
>      AL_Latch <= AVR_AD;

Diese Lösung hier entspricht genau dem, was ich ja auch gesagt habe.

@netbandit:
Also wenn Dein CPLD so voll ist, dass Pins getauscht werden müssen, 
damit es reinpasst, dann würde ich mir überlegen, ein größeres CPLD zu 
nehmen.
Ich hatte damals mit ISE7 ein XC9572 Design gemacht, welches auch 
randvoll war. Und da kamen plötzlich Probleme. Obwohl die Software das 
Design synthetisierte, lief das CPLD fehlerhaft. Entfernte ich nur eine 
kleine Funktion, so dass eine Makrozelle mehr frei war, lief alles so, 
wie geplant. Trotz tagelangem Suchen gelang es mir nicht, 
herauszufinden, was da passiert war.
Seitdem trau ich dem Xilinx-Ding nicht mehr und arbeite mit Altera.
Da ist mir trotz "Vollpacken bis zum Anschlag" noch nie dergleichen 
passiert. Benutze Altera MaxII EPM240 oder EPM570.

Wenn Du schon mit XC95144 am Ende bist, würde ich mir ein kleines FPGA 
überlegen. Ein größeres CPLD kostet schon über 10,- Euro und dafür 
bekommst Du schon ein kleines FPGA, in das viel mehr reinpasst.

Gruß

Joachim

von A. N. (netbandit)


Lesenswert?

@Holger:

>   process(AVR_ALE, AVR_AD, AVR_AH)
>   begin
>     if AVR_ALE = '1' then
>       AL_Latch <= AVR_AD;
>     end if;
>   end process;

Ja genau so hatte ich mir das ursprünglich mal vorgestellt...

>   process(AVR_WR, AVR_RD, AVR_AD, CS_Latch, Bank_Register)
>   begin
>     AVR_AD <= (others => 'Z');
>     if CS_Latch = "111" then
>       if AVR_WR = '0' then
>         Bank_Register <= AVR_AD;
>       else
>         if AVR_RD = '0' then
>           AVR_AD <= Bank_Register;
>         end if;
>       end if;
>     end if;
>   end process;

Und das geht bei mir auch nicht. Ich habe auch hier einen kleinen 
"Puffer" programmiert, der die Ausgänge nicht sofort umschaltet, nachdem 
das RD oder WR Signal wieder weg ist, sondern einen der die Ausgänge 
noch 3 CLK-Perioden länger aufhält. Ansonsten gibt es auch hier bei mir 
große Probleme, das Datum nicht richtig im Speicher gespeichert oder 
nicht richtig vom AVR gelesen wurde. (es war dann zu früh weg)

Wenn ich mir ansehe, wie trivial so eine Sache bei anderen Projekten 
funktioniert, denke ich, dass bei mir das grundlegende Problem ein ganz 
anderes ist. Ich bin schon die ganze zeit am Überlegen, wie ich den 
Testaufbau besser gestalten kann, aber irgendwie müssen halt die Signal 
von der AVR Platine zur CPLD Platine und weiter zur SRAM Platine kommen 
und somit entstehen nun einmal längere Leitungen.

Ich ätze mir auf jeden Fall keine Platine, bevor nicht das Design im 
CPLD steht und ich kann mir nicht vorstellen, das andere Projekte 
soetwas machen...

Holger, wie hast du das denn getestet? Hattest du deine Platine schon 
vor dir mit festgeschriebener Pinbelegung oder hast du auch einen 
Testaufbau benutzt?

Ich glaube ich reiße alles noch einmal ab und beginn von vorn. 
Vielleicht setze ich die Testplatinen huckepack, so kann man eventuell 
die Leitungswege noch einmal erheblich kürzen.

@Joachim

Naja, das will ich eigentlich aus Prinzip nicht machen :-) Ich baue 
einen kleinen LCD Controller, welcher ein 320*240 S/W LCD ohne eigenen 
Controller ansteuert. Soetwas in der Art wurde von Ulrich R. mit einem 
9572er erledigt (nur ohne XMEM-Interface, so dass ein lesen das 
Speichers vom AVR aus nicht möglich war) und von Benedikt, der das mit 
einer Handvoll Logikbausteinen realisiert, will ich hier gar nicht erst 
reden.
Mir erscheint der 95144 schon leicht zu Overkill für diese Aufgabe... 
und wenn ich nicht diese ganzen Probleme hätte könnte ich das 
XMEM-Interface, wie Holger völlig asyncron aufbauen und würde auch 
wesentlich weniger speicher benötigen - nur der LCD Teil müsste dann 
getaktet laufen... eine große Ersparnis an Makrozellen!

Ich werde noch einmal alles löschen, alle Leitungen abreißen und ganz 
langsam von vorne beginnen und schauen an welcher Stelle es bei mir 
hakt.

Aber da jetzt die Klausurzeit ansteht hab ich etwas wenig Zeit dafür... 
also mal sehen, spätestens Ende Juli, wenn alle Klausuren geschrieben 
sind stürze ich mich noch einmal in das Projekt.

von A. N. (netbandit)


Angehängte Dateien:

Lesenswert?

So,

gestern Abend habe ich noch einmal alles abgerissen und neu gemacht. 
Dabei hab ich die Testplatinen übereinander angeordnet, wodurch ein 
Kabel von einer Platine zur nächsten nun nur noch 3cm lang ist.

Und siehe da: Das Latch arbeitet jetzt völlig asynchron, so wie Holger 
es vorgeschlagen hat, bzw. wie ich es im Eingangspost beschrieben hatte. 
Auch der IO Buffer für die Tristateausgänge kann gleichzeitig mit RD/WR 
schalten.  Der AVR kann nun wieder mit 16MHz und völlig ohne Wait-States 
auf den Speicher zugreifen.

Also es hat alles nur an der Leitungslänge gelegen... hätte ich nicht 
gedacht.

Leider hat gestern die Zeit nicht mehr ausgereicht um noch die VHDL 
Routine zu integrieren, welche den Speicherinhalt wieder ausliest und an 
das LCD schickt. Aber das sind jetzt auch nur noch wenige Zeilen VHDL 
und die passen schon noch rein.

Ich hab mal ein Bild vom Aufbau angehangen und wenn alles gut geht kann 
ich ja heute Abend mal ein Bild vom funktionstüchtigen LCD reinstellen.

Ganz oben ist die Testplatine mit dem AVR, da drunter die mit dem CPLD 
und ganz unten ist die Testplatine mit dem SRAM.

Also dann noch einmal danke für eure Tips, und dass ich mich ein wenig 
ausheulen konnte :-)

Bis dann,
Netbandit

von A. N. (netbandit)


Angehängte Dateien:

Lesenswert?

So,

es hat noch einmal ne ganze Weile gedauert, bis ich fertig wurde. Gerade 
dann wenn der CPLD sich langsam füllt, fängt er an sehr ungünstig zu 
routen, wodurch es leicht zu Timingproblemen kommen kann. Nachdem ich 
jetzt alles hinter dem Latch vollsynchron aufgebaut habe läuft es aber.

Wie versprochen gibt es dazu auch ein Bild.

Natürlich gibt es noch viel Verbesserungsbedarf, vielleicht kann ich die 
Zahl der Functionblocks noch etwas reduzieren und die Timings noch etwas 
straffen (sind bisher recht großzügig ausgelegt, aber ein 15ns SRAM gibt 
halt auch etwas mehr her).

Aber mit diesen ganzen Verbesserungen werde ich mich nach der 
Klausurzeit genauer beschäftigen, jetzt bin ich erst einmal froh über 
meinen eigenen LCD-Controller.

Also dann bis zu meinem nächsten Problem ;)

Ciao,
Netbandit

von C. W. (cwi)


Lesenswert?

@Netbandit,
währe es möglich, deinen source für dein Projekt hier zu posten?
Wollte deine Lösung mal mit dem Pollin CPLD Board ausprobieren.

Danke
cwi

von A. N. (netbandit)


Lesenswert?

Hi,

ich würde es ungern hier Posten, da ich aus Zeitgründen das Projekt 
nicht 100% fertig stellen konnte. Es ist also noch im gleichen Stadium 
wie beim letzten Post von mir. Ich stelle ungern unfertige und damit 
auch nicht unbedingt gute Lösungen öffentlich zur Verfügung, sonst denkt 
noch jemand das muss man so machen ;)

Ich kann dir das jedoch gerne per Mail schicken. Schreib mir einfach 
eine PN und schreib rein ob du nur die VHDL Dateien oder auch den sehr 
provisorischen C-Code und eventuelle Schaltpläne (wenn ich die noch 
finde) brauchst, dann schicke ich dir das zu :)

Bis dann,
Netbandit

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.