XMEM - Mega1281 - Ganzen exterenen 64kB SRAm nutzen

Gast #557280
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
Gast #557310
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
Gast #557488
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
#557513
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.
1
#define RAM_OFFSET 0x2000
2

3
void init_sram(void){    
4
    MCUCR = _BV(SRE);//enable XRAM
5
}
6

7
void wr_ram(BYTE* adr, BYTE data){
8
   if(adr<(BYTE*)RAM_OFFSET){
9
      PORTC = 0;
10
      XMCRB = _BV(XMM1) | _BV(XMM0); //Maskiere obere Adr-Bits zu Null
11
      adr += RAM_OFFSET;         //Gültige XRAM-Adr vorgaukeln
12
      *adr = data;
13
      XMCRB = 0;
14
      return;
15
   }
16
   *adr = data;
17
}
18

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

24
BYTE rd_ram(BYTE* adr){
25
   BYTE dta;
26
   adr+=layeroffset;
27
   if((adr)<(BYTE*)RAM_OFFSET){
28
      PORTC = 0;
29
      XMCRB = _BV(XMM1) | _BV(XMM0); //Maskiere obere Adr-Bits zu Null
30
      adr += RAM_OFFSET;         //Gültige XRAM-Adr vorgaukeln
31
      dta=*adr;
32
      XMCRB = 0;
33
      return(dta);
34
   }
35
   dta=*adr;
36
   return(dta);
37
}
38

39
//Wenn sicher ist, dass adr>=RAM_OFFSET ist
40
BYTE rd_ram_i(BYTE* adr){
41
   return(*adr);
42
}
Gast #557597
Lesenswert?

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

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

lauten, kann mich aber auch irren, steht aber in der doku. binnur zu 
faul, grad bei atmel rumzuklickern :)
Moderator Persönliche Seite #557624
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...
Gast #557681
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
Moderator Persönliche Seite #557686
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.
Gast #558076
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
Moderator Persönliche Seite #558084
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren