Funktion aus Interrupt aufrufen

Gast #1337635
Lesenswert?

Hallo,
ich versuche grade, mit GCC ein kleines Programm für ARM (LPC2378) zu 
compilieren.
Das Programm verfügt über eine Interruptfunktion namens tick, die von 
einem Timer (Timer0) periodisch alle 1 ms aufgerufen wird.
So, der Interrupt und der Timer funktionieren föllig einwandfrei.
Jetzt möchte ich aber aus der Interruptfunktion heraus (also aus tick) 
eine andere Funktion aufrufen.
etwa so:

void tick(void) _attribute_ ((interrupt("FIQ")));

void tick(void)
{
  fTickHandler();
  T0IR = 0xFF;
  VICAddress = 0;
}

Das ganze funktioniert, aber nur, wenn ich es im RAM ausführe. Sobald 
ich es ins Flash lade, geht mein ganzes Programm nicht mehr.
Der GCC gibt auf jeden Fall eine Warnung aus:

Warning: writeback of base register is UNPREDICTABLE

Frage:
Was bedeutet das? Wie kann ich es beheben? Und warum funktioniert mein 
Programm nicht, obwohl es eigentlich einwandfrei ist?

Ich hoffe ihr könnt mir helfen.
Vielen Dank schon mal im Voraus!


PS:
Ach ja, mir fällt noch was ein.
Ich hatte (von einem früheren Experiment her) mal versehentlich folgende 
Code-Zeile stehen lassen:

void tick(void) _attribute_ ((interrupt("FIQ")));

anstatt

void tick(void) _attribute_ ((interrupt("IRQ")));

Das Programm hat aber in beiden Fällen funktioniert. Warum?
Gast #1338119
Lesenswert?

Hm, also ich habe damit noch keine Probleme gehabt (ADUC7026).

Allerdings habe ich die IRQ-Routinen anderst realisiert:
1
void (*IRQ)(void);
2
void  IRQ_Routine(void) __attribute__ ((interrupt ("IRQ")));
3
void IRQ_Routine(void) {
4
  if (*IRQ !=0x00) {
5
    IRQ();
6
  }
7
}
8

9
int main (void)  {
10
  IRQ = IRQ_Function;  // Weise IRQ Funkion zu
11
}
12

13
void IRQ_Function (void) {
14
}

Der Startup-Code ist nicht von mir:
vectors:       ldr     PC, Reset_Addr
                ldr     PC, Undef_Addr
                ldr     PC, SWI_Addr
                ldr     PC, PAbt_Addr
                ldr     PC, DAbt_Addr
                nop              /* Reserved Vector */
                ldr     PC, IRQ_Addr
                ldr     PC, FIQ_Addr

Reset_Addr:     .word   Reset_Handler    /* defined in this module below 
*/
Undef_Addr:     .word   UNDEF_Routine    /* defined in irq.c  */
SWI_Addr:       .word   SWI_Routine      /* defined in irq.c  */
PAbt_Addr:      .word   PAbt_Routine    /* defined in irq.c  */
DAbt_Addr:      .word   DAbt_Routine    /* defined in irq.c  */
IRQ_Addr:       .word   IRQ_Routine      /* defined in irq.c  */
FIQ_Addr:       .word   FIQ_Routine      /* defined in irq.c  */



Das ganze ist wegen der eigentlich unnötigen Sprüngen zu Beginn eines 
IRQ nicht umbedingt optimal, allerdings hatte ich bisher weder mit 
Funktionsaufrufen noch mit Optimierungen Probleme.

Allerdings hat mein uC keinen VIC, einige Dinge werden also anderst als 
bei dir sein.
Gast #1338190
Lesenswert?

@Tilo
danke, ich versuche es mal auf die Art wie du das machst.
Mal schauen, ob das Abhilfe bringt :-)
Wenns keine Möglichkeit gäbe, aus einer Interruptfunktion eine beliebige 
sonstige Funktion aufzurufen, dann wäre das ziemlich sch..... schade.
Ich muss im Timerinterrupt einen Haufen Sachen erledigen, es wäre 
ziemlich unübersichtlich (und wegen Modularität auch nicht gut) den 
ganzen Code in den Timerinterrupt rein zu packen.

Hat sonst noch niemand das Problem gehabt? :o Bin ich der einzige, der 
im Interrupt eine Funktion aufrufen will?
#1338194
Lesenswert?

Nein, bist du nicht. Aber vielleicht der einzige bei dem dieses Problem 
auftritt.

Wobei ich jedoch bei den ARMs einen zentralen Interrupt-Dispatcher 
verwende. Der IRQ landet in einer Assembler-Funktion, die die Register 
sichert, zur Unterstützung von verschachtelten Interrupts den Modus 
wechselt und dann als Handler über denn VIC-Vektor eine normale C 
Funktion aufruft. Die deshalb ggf. auch in Thumb codiert sein kann. Da 
kann das Problem nicht auftreten.
Gast #1338216
Lesenswert?

@A.K.:
Kann man sich deinen Startup-Code mit diesen Handlern einmal ansehen?

Bei mir ist einfach eine normale Vector-Tabelle, in dem Stil

vectors:
  b reset
  b undef
  b swi
  b pabort
  b dabort
  nop /* bootloader checksum */
  ldr pc, [pc, #-0x120]
  b fiq


im reset-Handler wird dann für jeden Modus der Stackpointer 
initialisiert, also undef, user, supervisor und so weiter. Nachher kommt 
ein

  b main
Gast #1338277
Lesenswert?

Hallo A.K.,
vielen dank für deinen Code.
Ich habe mal von der Seite, zu welcher du mir den Link angegeben hast, 
ein Beispiel runtergeladen (GPIO mit LPC23xx / LPC24xx).
Da raus habe ich mal testweise den Startup-Code übernommen; und was soll 
ich sagen? Intressanterweise hängt sich der Rechner immer beim 
Initialisieren des VIC auf. Sobald nämlich die ISR installiert werden 
soll, springt er in en dabort-Handler - irgendwie ganz merkwürdig.
Weisst du da was drüber?

Mein Code sieht wie folgt aus:

void tick(void) _attribute_ ((interrupt("IRQ")));

void test(void)
{
  static int a = 0;
  if(a)
    FIO1CLR = 0xFFFFFFFF;
  else
    FIO1SET = 0xFFFFFFFF;
  a = !a;
}

void tick(void)
{
  test();
  T0IR = 0xFF;
  VICAddress = 0;
}


void initmam(void)
{
  MAMTIM = 3;
  MAMCR = 2;
}

void initpll(void)
{
  IRCTRIM = 0xEE;
  PLLCON &= 0xFFFFFFFD;
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  PLLCON &= 0xFFFFFFFE;
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  CCLKCFG = 0;
  PLLCFG = 0x000700FC;
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  PLLCON |= 0x00000001;
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  CCLKCFG = 3;
  while(!(PLLSTAT & (1 << 26)));
  PLLCON |= 0x00000002;
  PLLFEED = 0xAA;
  PLLFEED = 0x55;b // 72 MHz
}

void initvic(void)
{
  VICIntEnClr = 0xFFFFFFFF;
  VICAddress = 0;
  VICIntSelect = 0;
  VICIntSelect = 0;
}

void inittimer(void)
{
  T0TCR = 0;
  T0PR = 0;
  T0MR0 = 18000;
  T0MCR = 0x03;
  T0TCR = 1;
  VICIntEnable = 0x10;
  VICVectPriority4 = 0;
  VICVectAddr4 = (unsigned long)tick;
}

void initsdram(void)
{
  int i;
  PCONP |= (1 << 11);
  PINSEL5 = 0x55010115;
  PINMODE5 = 0xAA02022A;
  PINSEL6 = 0x55555555;
  PINMODE6 = 0xAAAAAAAA;
  PINSEL7 = 0x55555555;
  PINMODE7 = 0xAAAAAAAA;
  PINSEL8 = 0x15555555;
  PINMODE8 = 0x2AAAAAAA;
  PINSEL9 = (1 << 18);
  PINMODE9 = 0x80000;
  EMCControl = 1;
  EMCDynamicReadConfig = 1;
  EMCDynamicRasCas0 = 0x203;
  EMCDynamictRP = 3;
  EMCDynamictRAS = 5;
  EMCDynamictSREX = 2;
  EMCDynamictAPR = 2;
  EMCDynamictDAL = 5;
  EMCDynamictWR = 3;
  EMCDynamictRC = 6;
  EMCDynamictRFC = 6;
  EMCDynamictXSR = 2;
  EMCDynamictRRD = 3;
  EMCDynamictMRD = 3;
  EMCDynamicConfig0 = ((1 << 14) | (1 << 10) | (1 << 9) | (1 << 7));
  for(i = 0; i < 100; i++);
  EMCDynamicControl = 0x181; // nop
  for(i = 0; i < 100; i++);
  EMCDynamicControl = 0x101; // pall
  EMCDynamicRefresh = 1; // ??
  for(i = 0; i < 100; i++);
  EMCDynamicRefresh = 19;
  EMCDynamicControl = 0x081;
  i = (*(volatile int*)(0xA0000000 | (0x22 << 13))); // 4 burst 2 cas
  EMCDynamicControl = 0;
  EMCDynamicConfig0 |= 0x80000;
}

int main(void)
{
  MEMMAP = 1;
  SCS |= 1;
  initmam();
  initpll();
  initsdram();
  initvic();
  inittimer();
  IO1DIR = FIO1DIR = 0xFFFFFFFF;
  IO1CLR = FIO1CLR = 0xFFFFFFFF;
  while(1)
  {

  }
}

und der Startup-Code sieht so aus:

  .text
  .code 32
  .global reset
  .align 0
  .arm
  .section .vectors, "ax"

start:
  b reset_vector
  b undef_vector
  b swi_vector
  b pabort_vector
  b dabort_vector
  .word 0x99FFFFD8 /* bootloader checksum */
  b irq_vector
  b fiq_vector

  .section .init, "ax"
  .code 32
  .align 0

reset_vector:
  b reset
undef_vector:
  b undef
swi_vector:
  b swi
pabort_vector:
  b pabort
dabort_vector:
  b dabort
irq_vector:
  b irq
fiq_vector:
  b fiq

undef:
  b undef

swi:
  b swi

pabort:
  b pabort

dabort:
  b dabort

irq:
  //ldr pc, [pc, #-0x154]
  sub lr, lr, #4
  stmfd sp!, {lr}
  mrs r14, SPSR
  stmfd sp!, {r14}
  stmfd sp!, {r0}
  ldr r14, =0xFFFFFF00
  ldr r0 , [r14]
  msr CPSR_c, #MODE_SVC
  stmfd sp!, { r1-r3, r12, r14 }
  mov r14, pc
  bx r0
  ldmia sp!, { r1-r3, r12, r14 }
  msr CPSR_c, #I_BIT | MODE_IRQ
  ldmia sp!, {r0}
  ldmia sp!, {r14}
  msr SPSR_cxsf, r14
  ldmia sp!, {pc}^

fiq:
  b fiq

reset:
  ldr r0, =STACK_TOP

  /* switch to UND mode and initialize its stack pointer */
  msr cpsr_c, #MODE_UND | I_BIT | F_BIT
  mov sp, r0
  sub r0, #UND_STACK_SIZE

  /* switch to ABT mode and initialize its stack pointer */
  msr cpsr_c, #MODE_ABT | I_BIT | F_BIT
  mov sp, r0
  sub r0, #ABT_STACK_SIZE

  /* switch to FIQ mode and initialize its stack pointer */
  msr cpsr_c, #MODE_FIQ | I_BIT | F_BIT
  mov sp, r0
  sub r0, #FIQ_STACK_SIZE

  /* switch to IRQ mode and initialize its stack ponter */
  msr cpsr_c, #MODE_IRQ | I_BIT | F_BIT
  mov sp, r0
  sub r0, #IRQ_STACK_SIZE

  /* switch to SVC mode and initialize its stack pointer */
  msr cpsr_c, #MODE_SVC | I_BIT | F_BIT
  mov sp, r0
  sub r0, #SVC_STACK_SIZE

  /* clear all pending interrupts */
  ldr r1, =VICINTENCLR
  mov r2, #0xFFFFFFFF
  str r2, [r1]

  /* clear all pending software interrupts */
  ldr r1, =VICSOFTINTCLR
  mov r2, #0xFFFFFFFF
  str r2, [r1]

  /* switch to USR mode and initialize its stack pointer */
  msr cpsr_c, #MODE_USR /* irq and fiq enabled */
  mov sp, r0
  sub sl, sp, #USR_STACK_SIZE

  ldr r0, =main
  bx r0
#1404521
Lesenswert?

A.K,
ich habe da auch mal eine Frage bez¨glich des Startup-Code.
Ich habe hier einiges mitgelesen und das auch auf meinen Code adaptiert, 
funktioniert alles bestens. Das einzige, was ich bisher weggelassen 
hatte, war diese Kopiererei ("Copy initialized data to its execution 
address in RAM") vom Flash ins RAM, weil mir nicht klar war wozu die gut 
sein sollte.
Danach hatte ich einige Probleme mit Variablen, die als static 
deklariert waren. Nach einfügen der Kopierfunktionen hat dann auch das 
geklappt.
Nun habe ich nur noch ein Problem. Und zwar wollte ich einen wirklich 
universellen Startup-Code bauen, der alles nötige initialisiert, sodass 
man auch mit C++ programmieren könnte (wenn man das denn wollte). Also 
muss ich vor dem main-Aufruf noch die C++ Konstruktoren aufrufen, und 
nach dem Beenden von main (was zwar nicht vorkommt, aber der 
vollständigkeit halber) die Destruktoren.
Soweit so gut; doch nachdem ich nun diesen Code noch eingefügt habe, der 
die Konstruktoren aufruft, kommt es in anderen Programmteilen zu 
sporadischen Abstürzen. Es ist reproduzierbar, tritt aber 
interessanterweise nur auf, wenn die Konstruktoren vorher aufgerufen 
wurden; ansonsten nicht. Was ich noch erwähnen sollte ist, dass in 
meinem Testprogramm C und C++ vermischt sind - C++ geht jetzt, dafür C 
nicht mehr ganz richtig. Wenn mehrere Funktionen ineinander 
verschachtelt sind und Rückgabewerte zurückgeben sollen, dann geht das 
nur bis zu einer bestimmten Tiefe, dann stürzt der Rechner ab, ich kann 
mir aber nicht erklären wieso.
Könntest du bitte meinen Code anschauen, und mir sagen, ob es an dem 
liegt? Wär super toll.


Gruss
     Tobias
Angehängte Dateien:

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