mikrocontroller.net

Forum: Compiler & IDEs XMEM - Mega1281 - Ganzen exterenen 64kB SRAm nutzen


Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo an alle,

Ich hab da mal eine Frage zum XMEM Interface des Mega1281 und Mega2561.

Ich hab nun einen 64kB SRAM an das Interface anghängt. Davon kann ich ja 
normal nur auf 56kB zugreifen, da die unteren 8kB die des internen SRAMs 
sind.

Ist es möglich de ganzen externen externen Ram zu nutzen?
Der Adresszeiger ist ja nur 16 Bit. Deshalb die Frage. Es steht ja dazu 
etwas im Datenblatt, aber das verstehe ich nicht wirklich.

Danke im Voraus
mfg Georg

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist leider nicht (direkt) möglich, da u.a. alle IO Register des AVRs 
diesen Platz belegen.
Verwendet man nur 32kB und schaltet A15 per Hand um (also quasi 
Banking), dann geht es.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

bin zufällig beim can128 drüber gestolpert, aber bei deiner mcu ist es 
nicht anders. PORTC wird benutzt, um das höherwertige adress-byte für 
den externen sram zu definieren. mittels der xmm-bits kannst du nun 
definieren, welche bits davon verwendet werden. wenn du (wie default 
vermutlich) alle 8 bits verwendet, gehen dir 8 kb ab wg internal sram. 
benutzt du weniger, so greift das nicht mehr und du hast zugriff auf die 
unteren bereiche des externen srams.

am beispiel des can128: der hat 4k sram == 0x0000 bis 0x1FFF. dafür 
müssen die obersten 3 bits ignoriert werden (bei 0x1FFF sind diese ja 
unbenutzt). ergo gibt die doku an, lediglich 5 bits des PORTC zu 
benutzen.

für den 1281: der hat wohl 8k sram == 0x0000 bis 0x2FFF. dafür müssen 
nur die obersten beiden bits von PORTC ignoriert werden. entsprechend 6 
nutz-bits dieses ports (XMM1 gesetzt, der rest 0).

hth,
bye kosmo

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok das hab ich einmal verstanden.

Jetzt in der PRaxis. Muss ich immer im XMM Register das umstellen, damit 
ich auf die unteren 8kB zugreife kann?

Ist so etwas sinnvoll??

mfg Georg

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg wrote:

> Jetzt in der PRaxis. Muss ich immer im XMM Register das umstellen, damit
> ich auf die unteren 8kB zugreife kann?

Ja.

> Ist so etwas sinnvoll??

Vermutlich nur im Ausnahmefall.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

>> Ist so etwas sinnvoll??
>
> Vermutlich nur im Ausnahmefall.


Ich denke auch, die Anwendung, die mit 72kB SRAM läuft, aber mit 63,5kB 
nicht mehr, die mußt Du schon mit der Lupe suchen.


Peter

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, wie macht man das bitte nit dem Umschalten? Wenn zB im unterren 
Bereich gearbeitet wird, und Interrupt auftritt dann muss ich daten am 
Stack ablegen...

Naja Ram brauch ich schon viel: TCP/IP, FAT, Display und AD-Wandler am 
XMEM Interface...

mfg

Autor: Frank N. (betafrank)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So sollte es gehen: Zur gewünschten XRAM-Adresse ggf. einen Offset 
addieren, um nicht im internen SRAM zu landen. Dann noch die höheren 
Adressleitungen mit 0 maskieren und es landet im XRAM an gewünschter 
Position.
#define RAM_OFFSET 0x2000

void init_sram(void){    
    MCUCR = _BV(SRE);//enable XRAM
}

void wr_ram(BYTE* adr, BYTE data){
   if(adr<(BYTE*)RAM_OFFSET){
      PORTC = 0;
      XMCRB = _BV(XMM1) | _BV(XMM0); //Maskiere obere Adr-Bits zu Null
      adr += RAM_OFFSET;         //Gültige XRAM-Adr vorgaukeln
      *adr = data;
      XMCRB = 0;
      return;
   }
   *adr = data;
}

//Wenn sicher ist, dass adr>=RAM_OFFSET ist
void wr_ram_i(BYTE* adr, BYTE data){
   *adr = data;
}

BYTE rd_ram(BYTE* adr){
   BYTE dta;
   adr+=layeroffset;
   if((adr)<(BYTE*)RAM_OFFSET){
      PORTC = 0;
      XMCRB = _BV(XMM1) | _BV(XMM0); //Maskiere obere Adr-Bits zu Null
      adr += RAM_OFFSET;         //Gültige XRAM-Adr vorgaukeln
      dta=*adr;
      XMCRB = 0;
      return(dta);
   }
   dta=*adr;
   return(dta);
}

//Wenn sicher ist, dass adr>=RAM_OFFSET ist
BYTE rd_ram_i(BYTE* adr){
   return(*adr);
}

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg wrote:

> Hi, wie macht man das bitte nit dem Umschalten? ...

> Naja Ram brauch ich schon viel: TCP/IP, FAT, ...

Du kannst ja einen der entsprechenden Puffer in diesen Bereich
auslagern.

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du kannst ja einen der entsprechenden Puffer in diesen Bereich
> auslagern.

Das hab ich mir auch gedacht. Nur wie schaut es aus, wenn ich auf den 
Puffer zugreife und dann ein IRQ auftritt?

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn ich mich recht an die doku von heut' vormittag erinnere ist das
      XMCRB = _BV(XMM1) | _BV(XMM0);

aber nicht korrekt, sollte
      XMCRB = _BV(XMM1);

lauten, kann mich aber auch irren, steht aber in der doku. binnur zu 
faul, grad bei atmel rumzuklickern :)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg wrote:

>> Du kannst ja einen der entsprechenden Puffer in diesen Bereich
>> auslagern.

> Das hab ich mir auch gedacht. Nur wie schaut es aus, wenn ich auf den
> Puffer zugreife und dann ein IRQ auftritt?

Du musst natürlich die Interrupts (oder die kritischen Interrupts)
für die Zeit blocken, während die Bänke umgeschaltet sind.  Das
betrifft ja in erster Linie den Bereich, der nach der Umschaltung
wirklich anders ist.  Der Bereich 8,5 KiB ... 32 KiB ist ja nicht
betroffen, den kannst du also für interruptfähige Daten benutzen.

Jaja, es gab mal Zeiten, da waren Bankumschaltungen bei Z80-Computern
sehr beliebt...

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du musst natürlich die Interrupts (oder die kritischen Interrupts)
> für die Zeit blocken, während die Bänke umgeschaltet sind.

Warum nur bei den kritischen? Sobald ein IRQ auftritt wird ja die 
dazugehörige ISR aufgerufen, und der Stack wird verändert...

Aber ich denke ich werde das ganze lassen... Das ganze wird sonst sehr 
aufwändig und beschränkt nutzbar...

Danek für die Antworten
mfg Georg

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg wrote:

>> Du musst natürlich die Interrupts (oder die kritischen Interrupts)
>> für die Zeit blocken, während die Bänke umgeschaltet sind.

> Warum nur bei den kritischen? Sobald ein IRQ auftritt wird ja die
> dazugehörige ISR aufgerufen, und der Stack wird verändert...

Den Stack lässt du sowieso am besten immer im internen RAM, schon
aus Geschwindigkeitsgründen.

Autor: kosmonaut_pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

>> Warum nur bei den kritischen? Sobald ein IRQ auftritt wird ja die
>> dazugehörige ISR aufgerufen, und der Stack wird verändert...

>Den Stack lässt du sowieso am besten immer im internen RAM, schon
>aus Geschwindigkeitsgründen.

womit sich mir folgende, selbstverständlich hypothetische frage 
aufdrängt:
was passiert, wenn man den SP dennoch auf eine externe adresse setzt, 
der stack jedoch in den bereich des internen srams wächst?
vermutlich wird dann der interne sram verwendet. gäbe es eine 
möglichkeit, das zu ändern?

bin nur neugierig,
danke, bye kosmo

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kosmonaut_pirx wrote:

> was passiert, wenn man den SP dennoch auf eine externe adresse setzt,
> der stack jedoch in den bereich des internen srams wächst?

Der interne SRAM ist immer eindeutig adressiert, insofern ist das
kein Problem.  Der Trick, um die unteren 8,5 KiB deines externen
Speichers zuzugreifen besteht ja darin, dass du die ganze untere
Hälfte des RAMs auf die 32-KiB-Grenze ,,umleitest''.  Der Bereich
oberhalb 40,5 KiB ist dann gespiegelt mit dem Bereich oberhalb
8,5 KiB, beide greifen also die gleichen Zellen zu.  Der Bereich
oberhalb 32 KiB (bezogen auf die tatsächlichen externen Adressen)
ist in diesem Modus komplett ausgeblendet.

Du kannst natürlich auf diese Weise auch den externen RAM einfach
in zwei 32 KiB große Speicherbänke aufteilen, die du dann manuell
(durch Setzen oder Löschen von A15 über den Portpin) umschaltest.
Die jeweils aktive Bank wird dann ab logischer Adresse 32 KiB
zugreifbar.  Die Applikation benutzt für Stack und normale Daten
den internen RAM.  Der logische Adressbereich von 8,5...32 KiB
wird nicht benutzt.  Damit könntest du z. B. in der einen
Speicherbank die Puffer für das FAT-Filesystem unterbringen und
in der anderen Bank die Puffer für den Netzwerkstack.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.