Forum: Compiler & IDEs "C" Will alle Variablen im ext. Speicher haben, aber wie mach ich das?


von Steffen H. (avrsteffen)


Lesenswert?

Hallo Leute,

Ich steh hier vor einem Problem, bei dem ich nicht weiter komm.

Ich habe hier ein Programm für einen XMega192A3 (16k SRAM) und möchte es 
in einen XMega128A1 (8k SRAM) portieren. Jetzt reicht der interne RAM 
Speicher des XMega128 leider nicht aus.

Ich habe allerdings SDRAM am XMega dran hängen und möchte dass der 
AVR-GCC all meine Variablen dorthin speichert.

Die Variablen sind fast alle in einem Struckt angelegt wie z.B. so hier:
1
struct controllerSingleton {    // main TG controller struct
2
  uint16_t magic_start;      // magic number to test memory integity  
3
  double null;          // dumping ground for items with no target
4
  uint8_t test;
5
  uint8_t src;          // active source device
6
  uint8_t default_src;      // default source device
7
  uint8_t linelen;        // length of currently processing line
8
  uint8_t led_state;        // 0=off, 1=on
9
  int32_t led_counter;      // a convenience for flashing an LED
10
  char in_buf[INPUT_BUFFER_LEN];  // input text buffer
11
  char out_buf[OUTPUT_BUFFER_LEN];// output text buffer
12
  char saved_buf[SAVED_BUFFER_LEN];// save the input buffer
13
  uint16_t magic_end;
14
};


Interner SRAM:   0x2000 - 0x3FFF  ( soll nur für den Stack bleiben)
Externer SDRAM:  0x4000 - 0xFFFF  ( für alle angelegten Variablen und 
Heap)

Reicht es im Makefile sowas wie hier

avr-gcc ... 
-Wl,--section-start,.data=0x804000,--defsym=__heap_end=0x80ffff

zu schreiben, oder muss ich noch mehr beachten und was hat es mit dem 
"malloc()" auf sich?

Den SDRAM muss ich natürlich auch noch initialisieren. In ASM war das 
für mich kein Problem und ich habe damit den SDRAM auch schon testen 
können.


Ich bin blutiger "C" Anfänger..


Gruß Steffen

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Von XMEGAs habe ich keine Ahnung aber da es wohl derselbe Compiler ist 
wird es wohl ähnlich gehen wie bei meinem ATMega2560 mit externem SRAM

Ich habe 2 Linker-Symbole definiert 
--defsym=__heap_start=0x802200,--defsym=__heap_end=0x80ffff

und dann muss auch noch sehr früh das Interface fürs externe RAM 
aktiviert werden.
1
// externes RAM aktivieren
2
void __attribute__ ((naked)) __attribute__ ((section (".init1"))) init_xram(void) {
3
    XMCRA = (1<<SRE);
4
}

von Steffen H. (avrsteffen)


Lesenswert?

Danke für die Antwort

M. K. schrieb:
> Ich habe 2 Linker-Symbole definiert
> --defsym=__heap_start=0x802200,--defsym=__heap_end=0x80ffff

Also reicht es eventuell schon, dem Linker zu sagen wo meine 
SRAM-Section beginnt und endet?

Und was hat es denn jetzt mit diesem *malloc()* auf sich?


Bin gerade dran das EBI im SDRAM - Mode zu initialisieren. Mal sehen ob 
das klappt.


Gruß Steffen

von M. K. (avr-frickler) Benutzerseite


Lesenswert?

Steffen H. schrieb:
> Und was hat es denn jetzt mit diesem *malloc()* auf sich?

Was ist jetzt genau deine Frage?
Also malloc() reserviert einen Speicherblock auf dem Heap.

Wenn du das ganze ein wenig debuggen möchtest, kannst du dir noch Zeiger 
auf den Anfang-/Ende des Heaps besorgen. Ausserdem gibt es noch einen 
Zeiger auf die aktuelle Größe des Heaps.
1
extern  char     *__malloc_heap_start, *__brkval, *__malloc_heap_end;   // Variablen für den heap

von Stefan E. (sternst)


Lesenswert?

Steffen H. schrieb:
> Also reicht es eventuell schon, dem Linker zu sagen wo meine
> SRAM-Section beginnt und endet?

Nein, was M.K. da gepostet hat, verlegt nur den Heap in das externe RAM, 
nicht aber die Variablen. Deine Variante war schon richtig.

Steffen H. schrieb:
> Und was hat es denn jetzt mit diesem malloc() auf sich?

Damit holt man sich dynamisch Speicher vom Heap.

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Also sollte es mit
1
avr-gcc ... -Wl,--section-start,.data=0x804000,--defsym=__heap_end=0x80ffff
machbar sein, wie oben im Bild angedeutet?


Gruß Steffen

von Stefan E. (sternst)


Lesenswert?

Ja.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn du kein malloc() benutzt, dann brauchst du dich um Dinge wie
__heap_end auch nicht kümmern.  Es reicht dann völlig, .data auf
den Anfang des externen SDRAM zu setzen (der Stack wird ja ohnehin
auf das obere Ende des internen SRAM initialisiert).

Allerdings musst du dich natürlich drum kümmern, dass das XMEM-
Interface frühzeitig genug initialisiert wird, so wie das oben
schon mit der entsprechenden Funktion in .init1 angedeutet war.

von Steffen H. (avrsteffen)


Lesenswert?

Okay, Danke

Bin immer noch am einbinden einer SDRAM Initialisierung. In ASM war das 
alles viel einfacher..
1
//*******************************************************************************************************
2
3
Init_extSDRAM:
4
//PORT-Settings for ext. SDRAM
5
  ldi    accu1, 0xFF
6
  sts    PORTH_DIR, accu1
7
  sts    PORTK_DIR, accu1
8
  ldi    accu1, 0xF0
9
  sts    PORTJ_DIR, accu1
10
  ldi    accu1, 0x0F
11
  sts    PORTH_OUT, accu1
12
13
// Config EBI
14
  ldi    accu1, EBI_SDDATAW_4BIT_gc + EBI_LPCMODE_ALE1_gc + EBI_SRMODE_ALE1_gc + EBI_IFMODE_3PORT_gc
15
  sts    EBI_CTRL, accu1
16
// Config SDRAM
17
  ldi    accu1, EBI_SDROW_bm + EBI_SDCOL_10BIT_gc
18
  sts    EBI_SDRAMCTRLA, accu1
19
20
  ldi    accu1, byte1(768);768
21
  sts    EBI_REFRESH, accu1
22
  ldi    accu1, byte2(768);768
23
  sts    EBI_REFRESH +1, accu1
24
25
  ldi    accu1, byte1(1023)
26
  sts    EBI_INITDLY, accu1
27
  ldi    accu1, byte2(1023)
28
  sts    EBI_INITDLY +1, accu1
29
30
// 1 cycle Mode Register Delay. + 7 cycle Row Cycle Delay. + 2 cycle Row to Pre-charge Delay
31
  ldi    accu1, EBI_MRDLY_1CLK_gc + EBI_ROWCYCDLY_7CLK_gc + EBI_RPDLY_2CLK_gc
32
  sts    EBI_SDRAMCTRLB, accu1
33
34
// 2 cycle Write Recovery Delay + 7 cycle Exit Self Refresh to Active Delay + 2 cycle Row to Column Delay
35
  ldi    accu1, EBI_WRDLY_2CLK_gc + EBI_ESRDLY_7CLK_gc + EBI_ROWCOLDLY_2CLK_gc
36
  sts    EBI_SDRAMCTRLC, accu1
37
38
  ldi    accu1, EBI_CS_SDMODE_LOAD_gc
39
  sts    EBI_CS3_CTRLB, accu1
40
41
  clr    accu1
42
  sts    EBI_CS3_BASEADDR, accu1
43
  sts    EBI_CS3_BASEADDR +1, accu1
44
45
  ldi    accu1, EBI_CS_ASPACE_16M_gc + EBI_CS_MODE_SDRAM_gc
46
  sts    EBI_CS3_CTRLA, accu1
47
48
.equ  EBI_CS_SDINITDONE = 7
49
Wait_SDRAM_Init1:
50
  lds    accu1, EBI_CS3_CTRLB
51
  sbrs  accu1, EBI_CS_SDINITDONE
52
  rjmp  Wait_SDRAM_Init1
53
54
  ldi    accu1, EBI_IFMODE_DISABLED_gc
55
  sts    EBI_CTRL, accu1
56
  ldi    accu1, EBI_CS_SDMODE_NORMAL_gc
57
  sts    EBI_CS3_CTRLB, accu1
58
  ldi    accu1, EBI_SDDATAW_4BIT_gc + EBI_LPCMODE_ALE1_gc + EBI_SRMODE_ALE1_gc + EBI_IFMODE_3PORT_gc
59
  sts    EBI_CTRL, accu1
60
61
Wait_SDRAM_Init2:
62
  lds    accu1, EBI_CS3_CTRLB
63
  sbrs  accu1, EBI_CS_SDINITDONE
64
  rjmp  Wait_SDRAM_Init2
65
  ret
66
67
//*******************************************************************************************************

Gruß Steffen

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Steffen H. schrieb:
> In ASM war das
> alles viel einfacher..

Ja dan bleib doch bei ASM... immer dieses 'genörgel' das mit XYZ 'alles 
einfacher war'... Wie einfach war das den als du gerade mit ASM 
angefangen hast?
Deine ganzen lid/sti orgine kannst du nun durch einfache Zuweisung 
lösen, Rücksprünge mit Abbruchbedingung durch eine while Schleife, was 
ist daran bitte "komplizierter"?

Und wenn du unbedingt darauf bestehst das ASM einfacher ist, du kannst 
ja auch in C ASM Code einbinden, oder sogar ganze ASM Module schreiben 
und einbinden...

Ob das aber einfacher ist als sich mal mit den Grundlagen zu 
beschäftigen...?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Läubi .. schrieb:
>> In ASM war das
>> alles viel einfacher..
>
> Ja dan bleib doch bei ASM... immer dieses 'genörgel' das mit XYZ 'alles
> einfacher war'... Wie einfach war das den als du gerade mit ASM
> angefangen hast?

;-)

Um mal zu zeigen, dass das in C wirklich nicht schlimmer ist:
1
#include <avr/io.h>
2
3
void
4
__attribute__ ((naked)) __attribute__ ((section (".init1")))
5
init_ebi(void) {
6
  //PORT-Settings for ext. SDRAM
7
  PORTH_DIR = 0xff;
8
  PORTK_DIR = 0xff;
9
  PORTJ_DIR = 0xf0;
10
  PORTH_OUT = 0x0f;
11
12
  // Config EBI
13
  EBI_CTRL = EBI_SDDATAW_4BIT_gc + EBI_LPCMODE_ALE1_gc +
14
             EBI_SRMODE_ALE1_gc + EBI_IFMODE_3PORT_gc;
15
  // Config SDRAM
16
  EBI_SDRAMCTRLA = EBI_SDROW_bm + EBI_SDCOL_10BIT_gc;
17
  EBI_REFRESH = 768;
18
  EBI_INITDLY = 1023;
19
20
  // 1 cycle Mode Register Delay. + 7 cycle Row Cycle Delay.
21
  // + 2 cycle Row to Pre-charge Delay
22
  EBI_SDRAMCTRLB = EBI_MRDLY_1CLK_gc + EBI_ROWCYCDLY_7CLK_gc +
23
                   EBI_RPDLY_2CLK_gc;
24
25
  // 2 cycle Write Recovery Delay + 7 cycle Exit Self Refresh
26
  // to Active Delay + 2 cycle Row to Column Delay
27
  EBI_SDRAMCTRLC = EBI_WRDLY_2CLK_gc + EBI_ESRDLY_7CLK_gc +
28
                   EBI_ROWCOLDLY_2CLK_gc;
29
  EBI_CS3_CTRLB = EBI_CS_SDMODE_LOAD_gc;
30
  EBI_CS3_BASEADDR = 0;
31
  EBI_CS3_CTRLA = EBI_CS_ASIZE_16M_gc + EBI_CS_MODE_SDRAM_gc;
32
  while ((EBI_CS3_CTRLB & EBI_CS_SDINITDONE_bm) == 0)
33
    { /* wait for SDRAM init */ }
34
  EBI_CTRL = EBI_IFMODE_DISABLED_gc;
35
  EBI_CS3_CTRLB = EBI_CS_SDMODE_NORMAL_gc;
36
  EBI_CTRL = EBI_SDDATAW_4BIT_gc + EBI_LPCMODE_ALE1_gc +
37
             EBI_SRMODE_ALE1_gc + EBI_IFMODE_3PORT_gc;
38
  while ((EBI_CS3_CTRLB & EBI_CS_SDINITDONE_bm) == 0)
39
    { /* wait for SDRAM init */ }
40
}

Ist also eigentlich alles dasselbe, außer dass man eine Zuweisung auch
über mehrere Zeilen schreiben kann, dass man sich keine „Akkus“ selbst
definieren muss, und dass man sich nicht um die Aufteilung der
16-bit-Register in high- und low-Bytes kümmern muss. ;-)

Ich habe es spaßeshalber für dich durch den Compiler geschoben um zu
sehen, ob es auch compiliert.  EBI_CS_ASPACE_16M_gc hat dem Compiler
nicht gefallen, da die Konstante offenbar EBI_CS_ASIZE_16M_gc heißt.
Hat dein Assemblercode wirklich so funktioniert?

(Ob das Ganze inhaltlich auch Sinn hat, weißt du natürlich nur selbst,
ich habe lediglich stupide deine Assemblerwust in C-Wust übertragen.)

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.