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
ifRESET='0'then
5
6
S_A_SRAM(7downto0)<=(others=>'0');
7
elsiffalling_edge(ALE_AVR)then
8
9
S_A_SRAM(7downto0)<=AD_AVR;
10
endif;
11
endprocess;
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
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.
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
ifALE_AVR='0'then
5
6
Z_LATCH<="00";
7
elsiffalling_edge(CLK)then
8
9
caseZ_LATCHis
10
11
when"11"=>
12
13
S_A_SRAM(7downto0)<=AD_AVR;
14
Z_LATCH<="11";
15
whenothers=>
16
17
Z_LATCH<=Z_LATCH+1;
18
endcase;
19
endif;
20
endprocessLATCH;
@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?
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.
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
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.
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
>>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
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
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
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.
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
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.
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
--hierReset
5
elsif(rising_edge(CLK))then
6
ifALE='1'then
7
Global_Address(15downto8)<=Address;
8
Global_Address(7downto0)<=ADBUS;
9
endif;
10
ifWR='0'then
11
HOST_WR_DATA<=ADBUS;
12
endif;
13
endif;
14
endprocess;
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
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.
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
"- 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.
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 :-)
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;
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
@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.
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
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
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