Forum: Compiler & IDEs ARM7 - Funktionen ins Ram kopieren


von Tilo (Gast)


Lesenswert?

Hallo

ich will einige Funktionen (arm-gcc) ins Ram kopieren, um deren 
Ausführzeiten zu beschleidnigen. Das Flash ist nur mit 16bit verbunden.

Unter http://www.embeddedrelated.com/groups/lpc2000/show/5031.php habe 
ich eine Diskussion über das Thema gefunden. Dort taucht folgender 
Abschnitt auf:

So to summarize, to get and use a function in RAM you only need to do
three things:

(1) Have an init in the startup code for the .data section.
(2) Use the __attribute__((section(".data"))) on the functions.
(3) Define function pointer variables for the functions and make
indirect calls using those.


Zu Punkt 1:
In meinem Startup-Code gibt es folgenden Abschnitt:
1
        /* copy initialized variables .data section  (Copy from ROM to RAM) */
2
                ldr     R1, =_etext
3
                ldr     R2, =_data
4
                ldr     R3, =_edata
5
1:            cmp     R2, R3
6
                ldrlo   R0, [R1], #4
7
                strlo   R0, [R2], #4
8
                blo     1b
9
10
        /* Clear uninitialized variables .bss section (Zero init)  */
11
                mov     R0, #0
12
                ldr     R1, =_bss_start
13
                ldr     R2, =_bss_end
14
2:        cmp     R1, R2
15
                strlo   R0, [R1], #4
16
                blo     2b
17
18
        /* Enter the C code  */
19
                b       main

Ich hab von Assembler nicht viel Ahnung. Wenn ich den Code richtig 
verstehe, wird die data Section hier ins Ram kopiert.

Zu Punkt 2:

Das ganze sollte also so aussehen:
1
void foo(void) __attribute__ ((section ("data")));


Soweit verstehe ich das ganze noch. Mit dem Attribut der der Compiler 
angewiesen, die Funktion in dem Bereich abzulegen, in dem die Variablen 
im Ram liegen. Im Startup-Code wird dann die Funktion vom Flash ins Ram 
kopiert.


Zu Punkt 3:

Es soll ein Pointer verwendet werden, um die Funktion anzusprechen, also
z.B.:
1
void *foopointer = &foo;
2
foopointer();


So, jetzt meine Fragen:
Funktioniert das ganze so wirklich?
Wofür wird der Umweg über den Pointer benötigt?

Vielen Dank,

Tilo

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das beantwortet Karl Olsen in der gleichen Diskussion:

Nice trick of just locating the RAM function in .data.

With main() in flash and IAP_Test() in RAM, they are ~1GB apart, and
a normal BL instruction can only handle distances of up to +/- 32 MB.
Try calling it indirectly:

static void (*pramfunc)(void) = IAP_Test;
(*pramfunc)();

Dirch den Funktionszeiger soll Maschinencode erzeugt werden, der sog. 
long calls ermöglicht. Nicht die üblichen, platzsparenderen short calls 
innerhab der üblichen Flash-Adressbereiche.

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Evtl. einfacher: _attribute_ ((long_call, section (".data"))) und 
Funktion wie üblich aufrufen.

von Tilo (Gast)


Lesenswert?

Danke für eure Antworten.

Das hier funktioniert:
1
..
2
void DAC_Aquiredata(void) __attribute__ ((section (".data")));
3
4
void DAC_Aquiredata(void) {
5
...

Das hier hingegen nicht:
1
..
2
void DAC_Aquiredata(void) __attribute__ ((long_call, section (".data")));
3
4
void DAC_Aquiredata(void) {
5
...

dac.c:96: error: conflicting types for 'DAC_Aquiredata'
dac.h:6: error: previous declaration of 'DAC_Aquiredata' was here


So, nun bin ich etwas verwirrt. Unter 
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#gcc_ramfunc
habe ich ei Beispiel gefunden. Ich verwende einen aduc, das Beispiel ist 
für einen lpc. Sollte aber dem GCC egal sein.

In diesem Beispiel wurde das so gemacht:
1
#define FASTRUN __attribute__ ((long_call, section (".data")))
2
3
extern FASTRUN void setLED1(int on);
4
FASTRUN void setLED1(int on)
5
6
{

Das funktioniert so bei mir auch. Leider gibt der Compiler eine Warnung 
aus:
Warning: ignoring changed section attributes for .data
Laut http://www.spinics.net/lists/arm-kernel/msg24864.html ist das so, 
da in diesem Bereich kein Code ausgeführt werden darf. Das kann ich in 
diesem Fall dann acuh nachvollziehen. Ich weiß aber nicht, warum das so 
ist. Muss irgend wo noch markiert werden, welcher Code ausgeführt werden 
darf?

Ich hab die von mir verwendete Datei, in der die Sektionen definiert 
sind, angehängt. Sieht da einr von euch etwas dran?

Fehlt eine Option in der Makefile?

Danke, Tilo

von Karl (Gast)


Lesenswert?

Keine Datei dabei. Ich rate mal: Im Linkerscript haben die einzelnen 
Bereiche die Attribute r,w,x.
1
MEMORY
2
{
3
  FLASH (rx) : ORIGIN = 0x00100000, LENGTH = 0x00040000
4
  DATA (rw)  : ORIGIN = 0x00200000, LENGTH = 0x00010000
5
  STACK (rw) : ORIGIN = 0x00210000, LENGTH = 0x00000000
6
}

stammt zwar aus nem AT91 script, aber das soll mal nicht stören.

von Tilo (Gast)


Lesenswert?

Hallo

Ich habe den Dateianhang leider vergessen.
Im Linkerskript sind die Speicherbereiche so definiert:
1
MEMORY 
2
{
3
  /* flash  : ORIGIN = 0x00080000,          LENGTH = 62K    /* FLASH EPROM, the last 2K are used for the bootloader    */  
4
  flash  : ORIGIN = 0x0,          LENGTH = 62K    /* FLASH EPROM, the last 2K are used for the bootloader    */  
5
  ram  : ORIGIN = 0x00010000, LENGTH = 8K    /* static RAM area  */
6
}

rw ist nirgends angegeben. Die Data-Sektion sieht jetzt so aus:
1
  .data :                /* collect all initialized .data sections that go into RAM  */ 
2
  {
3
    _data = .;            /* create a global symbol marking the start of the .data section  */
4
    *(.data)            /* all .data sections  */
5
    *(.ramrun)            /* Section for functions which should be load to ram */
6
    _edata = .;            /* define a global symbol marking the end of the .data section  */
7
  } >ram AT >flash                /* put all the above into RAM (but load the LMA initializer copy into FLASH)  */

.data konnte ich nicht verwenden. Also legte ich einen zusätzlichen 
Bereich .ramrun an. Damit funktioniert das ganze nun.

von Veikko W. (fischbohne)


Lesenswert?

Hallo,

da bin ich ja über etwas interessantes gestolpert...

Muß man beim GCC etwas beachten -mlong-calls  o.Ä.

Gruß,
fischbohne

von Tilo (Gast)


Lesenswert?

Hallo

Also ich hab keine speziellen Parameter in der Makefile drin. (GCC 
4.2.2)

Ich wollte einen Sinus (DSS) über einen DAC ausgeben. Auf dem Oszi hat 
man deutlich gesehen, dass (bei mir) SRAM deutlich schneller als FLASH 
ist.

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

-mlong-calls is meines Wissens in "pauschales" _attribute_ (long_call) 
für alle Funktionen und dürfte ein wenig an der Performance knabbern. 
Ist allerdings die simpelste Lösung, um um die Sprungweitenbegrenzung 
herumzuarbeiten. Selektiver mit dem o.g. Ansatz.

BTW: in einem der Beträge oben:
>dac.c:96: error: conflicting types for 'DAC_Aquiredata'
>dac.h:6: error: previous declaration of 'DAC_Aquiredata' was here
sieht nach Unterschied in Deklaration (.h) und Definition (.c) der 
Funktion aus. Aber Problem hat sich ja schon vor längerem in 
wohlgefallen aufgelöst.

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.