Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt LPC2148 Yagarto


von Jansus (Gast)


Lesenswert?

Hallo Zusammen,

bin gerade völlig mit den Nerven runter. Habe schon den ganzen Tag 
versucht einen einfachen Timerinterrupt zu erleben.
Ich verwende Yagarto mit Eclipse usw. Der Controller ist ein LPC2148.

Habe den Timer konfiguriert:
TIMER0_MCR = 0x0003;
TIMER0_MR0 = 0x3E8;
TIMER0_TCR = 1;

Das VIC-Zeugs ebenfalls:
VICVectCntl0=0x20|4;
VICVectAddr0=(unsigned long )timer0;
VICIntEnable = 0x00000010;

Meine Interruptroutine schaut so aus:

void timer0(void) {
  TIMER0_IR=1;

  timercounter++;

  VICVectAddr=0;
}

Der Prototyp so:
void timer0(void) _attribute_ ((interrupt("IRQ")));


Vielleicht hat von Euch ja jemand noch mehr aktive Zellen um den Fehler 
zu finden.

Kann es sein, dass es so eine Art Global Interrupt Enable gibt? Wenn ja, 
wie rufe ich es auf?

Viele Grüße
Jansus

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Jansus wrote:
>...
> Kann es sein, dass es so eine Art Global Interrupt Enable gibt?
>...

Ja, gibt es. Am einfachsten beim Startup dafür sorgen, dass I_BIT und 
F_BIT im CPSR des Modus, von dem aus main() aufgerufen wird, nicht 
gesetzt sind. Wie im Detail, kann man erst schreiben, wenn Startup-Code 
gezeigt wird. Irgendwo im Startup Assembler-Code werden die 
Stack-Pointer der verschiedenen Modi gesetzt. In der letzten Zeile mit 
der Form msr CPSR_c... schauen, ob ein |I_BIT|F_BIT am Ende steht (oder 
|0x80|0x40). Wenn ja, löschen (denn I_BIT gesetzt heisst IRQ-Exceptions 
aus).
Ansonsten, falls Code im System-Mode ausgeführt wird (üblich bei 
"kleinen" ARM), kann man auch zur Laufzeit de-/aktivieren. In der Art:
1
#define IRQ_MASK 0x00000080
2
3
static inline unsigned long get_cpsr(void)
4
{
5
  unsigned long retval;
6
  asm volatile ("mrs  %0, cpsr" : "=r" (retval) : /* no inputs */  );
7
  return retval;
8
}
9
10
static inline void set_cpsr(unsigned long val)
11
{
12
  asm volatile ("msr  cpsr, %0" : /* no outputs */ : "r" (val)  );
13
}
14
15
void enableIRQ(void)
16
{
17
  unsigned long cpsr;
18
19
  cpsr = get_cpsr();
20
  set_cpsr(cpsr & ~IRQ_MASK); // clear I_BIT in CPSR
21
}

Timer-init habe ich jetzt nicht genau nachvollzogen, ist immer etwas 
mühsam mit Hex-Zahlen "Wüsten".

Ansonsten gibt es noch ein paar potentielle Fallen:
- _attribute_ ((interrupt("IRQ"))) funktioniert nicht in allen 
"Lebenslagen" bein arm GCC
- IRQ-Exceptions-Vector muss PC aus der Vic-Addresse laden, falls kein 
Assembler-Wrapper genutzt wird. Im Startup sollte bei LPC2000 (<2300) am 
siebten Vektor sowas stehen:
ldr pc,[pc,#-0xFF0]

Martin Thomas

von Jansus (Gast)


Lesenswert?

Hallo,

vielen Dank für die schnelle Antwort!
Habe inzwischen rausgefunden dass es wohl unterschiedliche Startupcodes 
gibt. Mal mit Interrupt-Fähigkeit, mal ohne.
Da meiner recht kurz ausfällt, befürchte ich, dass ich den ohne 
Interruptfunktionalität erwischt habe.
Leider bin ich ein absoluter Newbie was die ARMs angeht... Wie kann ich 
die oben genannten Funktionen verwenden? Wenn ich sie mir einfach in den 
Code reinkopiere, endet das im Absturz...
Ich fände es schon etwas praktischer, wenn ich Interrupts im laufenden 
Programm de- bzw. aktivieren könnte.
Schonmal herzlichen Dank im Voraus!!!


Hier mal mein Startup-Code
/* 
************************************************************************ 
***************************************

  crt.s            STARTUP  ASSEMBLY  CODE
                -----------------------


  Module includes the interrupt vectors and start-up code.

  ************************************************************************ 
***************************************  */

/* Stack Sizes */
.set  UND_STACK_SIZE, 0x00000004    /* stack for "undefined instruction" 
interrupts is 4 bytes  */
.set  ABT_STACK_SIZE, 0x00000004    /* stack for "abort" interrupts is 4 
bytes                  */
.set  FIQ_STACK_SIZE, 0x00000004    /* stack for "FIQ" interrupts  is 4 
bytes               */
.set  IRQ_STACK_SIZE, 0X00000004    /* stack for "IRQ" normal interrupts 
is 4 bytes          */
.set  SVC_STACK_SIZE, 0x00000004    /* stack for "SVC" supervisor mode 
is 4 bytes          */



/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs 
(program status registers) */
.set  MODE_USR, 0x10                /* Normal User Mode 
*/
.set  MODE_FIQ, 0x11                /* FIQ Processing Fast Interrupts 
Mode             */
.set  MODE_IRQ, 0x12                /* IRQ Processing Standard 
Interrupts Mode           */
.set  MODE_SVC, 0x13                /* Supervisor Processing Software 
Interrupts Mode       */
.set  MODE_ABT, 0x17                /* Abort Processing memory Faults 
Mode             */
.set  MODE_UND, 0x1B                /* Undefined Processing Undefined 
Instructions Mode     */
.set  MODE_SYS, 0x1F                /* System Running Priviledged 
Operating System Tasks  Mode  */

.set  I_BIT, 0x80                   /* when I bit is set, IRQ is 
disabled (program status registers) */
.set  F_BIT, 0x40                   /* when F bit is set, FIQ is 
disabled (program status registers) */


.text
.arm

.global  Reset_Handler
.global _startup
.func   _startup

_startup:

# Exception Vectors

_vectors:       ldr     PC, Reset_Addr
                ldr     PC, Undef_Addr
                ldr     PC, SWI_Addr
                ldr     PC, PAbt_Addr
                ldr     PC, DAbt_Addr
                nop              /* Reserved Vector (holds Philips ISP 
checksum) */
                ldr     PC, [PC,#-0xFF0]  /* see page 71 of "Insiders 
Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin  */
                ldr     PC, FIQ_Addr

Reset_Addr:     .word   Reset_Handler    /* defined in this module below 
*/
Undef_Addr:     .word   UNDEF_Routine    /* defined in main.c  */
SWI_Addr:       .word   SWI_Routine      /* defined in main.c  */
PAbt_Addr:      .word   UNDEF_Routine    /* defined in main.c  */
DAbt_Addr:      .word   UNDEF_Routine    /* defined in main.c  */
IRQ_Addr:       .word   IRQ_Routine      /* defined in main.c  */
FIQ_Addr:       .word   FIQ_Routine      /* defined in main.c  */
                .word   0          /* rounds the vectors and ISR 
addresses to 64 bytes total  */


# Reset Handler

Reset_Handler:

        /* Setup a stack for each mode - note that this only sets up a 
usable stack
        for User mode.   Also each mode is setup with interrupts 
initially disabled. */

          ldr   r0, =_stack_end
          msr   CPSR_c, #MODE_UND|I_BIT|F_BIT   /* Undefined Instruction 
Mode  */
          mov   sp, r0
          sub   r0, r0, #UND_STACK_SIZE
          msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT   /* Abort Mode */
          mov   sp, r0
          sub   r0, r0, #ABT_STACK_SIZE
          msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT   /* FIQ Mode */
          mov   sp, r0
           sub   r0, r0, #FIQ_STACK_SIZE
          msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT   /* IRQ Mode */
          mov   sp, r0
          sub   r0, r0, #IRQ_STACK_SIZE
          msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT   /* Supervisor Mode */
          mov   sp, r0
          sub   r0, r0, #SVC_STACK_SIZE
          msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT   /* User Mode */
          mov   sp, r0

        /* copy .data section (Copy from ROM to RAM) */
                ldr     R1, =_etext
                ldr     R2, =_data
                ldr     R3, =_edata
1:            cmp     R2, R3
                ldrlo   R0, [R1], #4
                strlo   R0, [R2], #4
                blo     1b

        /* Clear .bss section (Zero init)  */
                mov     R0, #0
                ldr     R1, =_bss_start
                ldr     R2, =_bss_end
2:        cmp     R1, R2
                strlo   R0, [R1], #4
                blo     2b

        /* Enter the C code  */
                b       main

.endfunc
.end

von Jansus (Gast)


Lesenswert?

Ich blicke einfach nicht durch! Gibt's nicht vielleicht irgendwo eine 
Art Tutorial in dem Startup-Codes erklärt werden?

Zurück zu dem, den ich benutze. Was muss ich tun, um den gewünschten 
Mode einzuschalten? Und muss ich aus den 0x80 0x00 machen, um Interrupts 
generell zu aktivieren?
Was ist eigentlich der Unterschied zwischen User und Systemmode?

???

von Jansus (Gast)


Lesenswert?

So, habe in einem Tutorial von Jim Lynch die Files VIClowlevel.c und .h 
gefunden.
Bin sie durchgegangen und kann sie glücklicherweise nachvollziehen. 
Passt ja auch sehr zu der Antwort von Martin Thomas.
Habe die Dateien jetzt mal in mein Projekt eingebunden.
Compilieren und debuggen funktioniert.
Allerdings bleibt der µC in "asm_set_cpsr" hängen, bzw. führt die Zeile 
"asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );" 
nicht aus.
Hat jemand eine Idee oder einen Tipp für mich?

von Wolfgang (Gast)


Lesenswert?

Hi,

ich hatte auch mal das gleiche Problem, also dass er diesen Befehle 
nicht kompiliert bzw. nicht ausführt ( Im Dissambly war er wegoptimiert 
worden.. ) musste dann leider für das Setzen der Interruptflags 2 
Assembler Funktionen schreiben. Das hat dann eigentlich problemlos ( 
dank freundlicher Hilfe hier im Forum ) funktioniert.

Thread:

Beitrag "ARM Nested Interrupts mit Keil µVision mit RealView?"

von Jansus (Gast)


Lesenswert?

Danke für die Antwort!
Leider weiß ich mit Assembler nicht so viel anzufangen.
Aber es war schon die Datei Nested_IRQ.s gemeint, oder? Was muss ich mit 
nested_irq_enable anstellen, damit es klappt? Ist das dann ein Ersatz 
für "asm volatile (" msr  cpsr, %0" : /* no outputs */ : "r" (val)  );"
oder funktioniert meine obige Zeile dann erst?

von Jansus (Gast)


Lesenswert?

Was mich etwas wundert: Das get_cpsr funktioniert ja, nur das set_cpsr 
nicht.

von mthomas (Gast)


Lesenswert?

Im gezeigten Startup-Script wird main() im System-Mode mit deaktivierten 
IRQ- und FIQ-Exceptions ausgeführt:
1
...
2
msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT   /* User Mode */
3
...
(der Kommentar irreführend)
Hatte bereits weiter oben geschrieben, dass das I_BIT nicht gesetzt sein 
darf, um IRQ-Exceptions zu aktivieren. Also testweise ändern in:
1
...
2
msr   CPSR_c, #MODE_SYS  /* I_BIT cleared -> IRQ-Exception enabled, same for FIQ */
3
...

inline-assembler "Geschichte" erstmal weglassen, kann man später immer 
noch nach schauen, wenn die eigentliche Interrupt-Verarbeitung 
funktioniert.


Martin Thomas

von Jansus (Gast)


Lesenswert?

Also ich hab's mal getestet.
Einziger Effekt ist, dass mir alles abschmiert sobald ich den Timer 
aktivieren will (TIMER0_TCR = 0x1;).

von mthomas (Gast)


Lesenswert?

Obwohl "alles abschmiert" erstmal ein Fortschritt, zumindest passiert 
jetzt etwas und dies wahrscheinlich dann, wenn der Interrupt auslöst.

- VIC vor Aktivierung des Timer-Interrupts (TCR) eingestellt? Mglw. 
läuft der Interrupt noch ins Leere (Timer Match-Interrupt "feuert" da 
schon aktiviert aber VIC noch nicht entsprechend eingerichtet). 
IRQ-Exceptions sind ja bereits vom Startup global freigegben. Diese 
Reihenfolge mal ausprobieren:
(1) MCR, MRO    (init timer)
(2) "VIC Zeugs" (configure VIC for Timer)
(3) TCR         (enable timer)

- Default Interrupt Handler eingerichtet (Function auf die 
VICDefVectAddr zeigt)? Wird dieser aufgerufen? Default-Handler sollte 
man bei LPC2000 mit VIC190 (z. Zt. die <2300) immer einrichten, hilft 
nicht nur bei "spurious interrupts" sondern auch bei der Suche nach 
Fehlern in der VIC-Konfiguration.

Martin Thomas

von mthomas (Gast)


Lesenswert?

ups, sorry: statt "...Aktivierung des Timer-Interrupts..."  "Aktivierung 
des Timers"

von Jansus (Gast)


Lesenswert?

Die Reihenfolge habe ich richtig. Erst VIC dann Timer. Aktiviere den 
Timer auch erst kurz vor meiner Endlosschleife.
VICDefVectAddr habe ich überhaupt nicht verwendet. Ich dachte 
"VICVectAddr0=(unsigned long )timer0;" würde alles managen?
Wie verwende ich VICDefVectAddr korrekt? Weise ich dem eine andere 
Interrupt-Routine zu?
Übrigens vielen, vielen Dank für die Tipps!

von Jansus (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe inzwischen einen anderen Startup-Code und ein anderes Makefile 
verwendet. Habe meinen C-Code "integriert" und wer sagt's, Eclipse 
kompiliert und debuggt.
Jedenfalls weiß ich jetzt was passiert. Wenn mal wieder alles 
abschmiert, steht im Disassembler "0x400000e0 <IRQHandler>:   b 
0x400000e0 <IRQHandler>". Der Interrupt löst aus, aber ich lande nicht 
in meiner Routine.
Nur dummerweise weiß ich hier nicht weiter...
Habe Makefile und Startup mal angehängt (wenn's klappt)

von Jansus (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch das makefile

von Jansus (Gast)


Lesenswert?

Okay, ich hab's! Muss im Startup statt IRQHandler halt meine Routine 
reinschreiben.
Aber wie schaut's dann aus, wenn ich mehrere IRQ-Interrupts managen 
möchte?

von Jansus (Gast)


Lesenswert?

Da habe ich schon wieder was dazu gelernt.
Ich muss wohl einen IRQHandler selbst basteln und im Startup 
integrieren.

Heißt das ich muss:
1. Register retten - aber welche?
2. Herausfinden wer oder was den Interrupt ausgelöst hat und dann in die 
entsprechende Routine springen - aber wie?
3. Register wieder zurückschreiben und Programm weiterlaufen lassen

Stimmt das soweit?
Hat das vielleicht schonmal jemand gemacht?

von Wolfgang (Gast)


Lesenswert?

Wenn du in C programmierst, was ich annehme, sollte eigentlich der 
Compiler alle Register sichern. Was du per Hand retten musst ist das 
Linkregister. Es sei denn dir reicht es, dass mehrere Interrupts 
auftreten können, aber keine Priorisierung stattfindet. Für eine 
Priorisierung brauchst du Nested Interrupts ( die 2 Assembler Funktionen 
von vorher retten hier das Linkregister und "enablen" wieder alle 
Interrupts ).
Das Linkregister musst du retten, da es für den IRQ Modus nur eines gibt 
und bei einem weiterem Interrupt wäre nun deine Rücksprungadresse 
verloren und du würdest im Nirgendwo landen, wenn du die ISR verlässt.
Damit diese Priorisierung möglich ist, musst du im Startup folgendes 
ändern:


_vectors:
   ldr pc, ResetAddr    /* Reset                 */
   ldr pc, UndefAddr    /* Undefined instruction */
   ldr pc, SWIAddr      /* Software interrupt    */
   ldr pc, PAbortAddr   /* Prefetch abort        */
   ldr pc, DAbortAddr   /* Data abort            */
   ldr pc, ReservedAddr /* Reserved              */
   ldr pc, IRQAddr      /* IRQ interrupt         */
   ldr pc, FIQAddr      /* FIQ interrupt         */

in

_vectors:
   ldr pc, ResetAddr       /* Reset                   */
   ldr pc, UndefAddr       /* Undefined instruction   */
   ldr pc, SWIAddr         /* Software interrupt      */
   ldr pc, PAbortAddr      /* Prefetch abort          */
   ldr pc, DAbortAddr      /* Data abort              */
   LDR pc, [pc, #-0x0FF0]  /* Vector from VicVectAddr */
   ldr pc, FIQAddr         /* FIQ interrupt           */

ich hoffe, dass ich nichts übersehen habe.

von Andreas K. (a-k)


Lesenswert?

Lasst die Sache mit nested Interrupts vorerst bleiben. Das ist was für 
Fortgeschrittene. Bleib bei einfachen Interrupts ohne IRQ-Handler in 
Assembler.

Der Befehl
    ldr     PC, [PC,#-0xFF0]
an der Stelle vom IRQ-Einsprung war schon also richtig. Da wird der 
Vektor von VIC geholt und ein eigener Assembler IRQ-Handler ist 
überflüssig.

Kleiner Nachteil: Ein sehr versionsresistenter GCC-Bug kann in 
Einzelfällen zu einem fehlerhaften IRQ-Handler führen. Das Risiko 
solltest du vorerst eingehen, und ggf. den vom Compiler erzeugten Code 
überprüfen. IIRC wird manchmal bei der Handhabung der Return-Adresse 
zweimal 4 abgezogen, einmal vorneweg, einmal hinten.

von Jansus (Gast)


Lesenswert?

Vielen Dank!
Ich habe die Zeile ausgetauscht und unten wieder IRQHandler anstatt 
meiner Routine eingesetzt.
Leider passiert jetzt wieder garnichts. Meine Endlosschleife wird 
ausgeführt, aber von Interrupts keine Spur.
Muss ich nicht irgendwie die Zuordnung von dem Interrupt zu dem 
IRQHandler herstellen?
Priorisierung möchte ich schon, aber ich bin erstmal schon unheimlich 
glücklich wenn ich zwei Interrupts (beide IRQ, aber unterschiedliche 
Quellen) hinbekomme.

von Jansus (Gast)


Lesenswert?

Der Disassembler sagt mir jetzt, dass ich im FIQHandler gelandet bin...

von Andreas K. (a-k)


Lesenswert?

Du musst den VIC programmieren. Sonst geht garnichts. Aber das tust du 
schon (ob richtig habe jetzt ich nicht kontrolliert).

Zudem wird in den Startups üblicherweise und richtigerweise der 
Interrupt noch nicht freigegeben. Das sollte nach der 
Basisinitialisierung im Programm erfolgen. Dazu siehe die Funktionen von 
Martin Thomas oben.

Ob der Interrupt überhaupt ausgelöst wird und bei VIC ankommt, kannst du 
testhalber in der Schleife per Abfrage des Interrupt-Flag Registers vom 
VIC rausfinden.

Im oben gezeigten Startup ist der IRQ-Stack zu klein. Sieh da lieber mal 
256 Bytes vor (dein Handler braucht zwar weniger, aber das wird sicher 
mal mehr).

Wenn der Controller bei CPSR auf die Nase fällt, dann möglicherweise 
weil er genau dann einen Interrupt verpasst bekommt und stecken bleibt.

Für's Debugging per JTAG ist bei LPC2000ern hilfreich, wenn im 
Startup-Code als erstes eine mächtige Zählschleife sitzt, die die ersten 
paarhundert Millisekunden abläuft, bis der Debugger die CPU nach dem 
Reset eingefangen hat. Das ist ein Konstruktionsfehler der LPCs: JTAG 
kann den Prozessor nicht sofort aus Reset einfangen, sondern der läuft 
unkontrolliert los und irgendwann später kriegt das JTAG ihn zu fassen. 
Wenn da die Initialisierung schon durch ist, gibt's allerlei unlustige 
Effekte.

von Andreas K. (a-k)


Lesenswert?

Ach ja: Beim LPC2138 ist vor dem ersten RAM-Zugriff eine spezielle 
Initialierung erforderlich. Kann sein, dass der LPC2148 das auch 
benötigt => Errata Sheet. Siehe irgendwelchen Startup-Codes im Netz, in 
manchen wird sich das sicher finden lassen.

von Jansus (Gast)


Lesenswert?

Bin aktuell am zweiten Startup dran, da ich mit dem Skript wenigstens 
einen Interrupt erleben konnte. Aber auch nur wenn ich unten meine 
Routine unter IRQHandler eingetragen hatte und nicht die Zeile "ldr pc, 
[pc, #-0x0FF0]  /* Vector from VicVectAddr */" sondern "ldr pc, IRQAddr" 
drinstehen hatte.
Wegen der Zählschleife. Sind dafür die paar nops gedacht? Ist das 
überhaupt genug?


/*
 * Some defines for the program status registers
 */
   ARM_MODE_USER  = 0x10      /* Normal User Mode 
*/
   ARM_MODE_FIQ   = 0x11      /* FIQ Fast Interrupts Mode 
*/
   ARM_MODE_IRQ   = 0x12      /* IRQ Standard Interrupts Mode 
*/
   ARM_MODE_SVC   = 0x13      /* Supervisor Interrupts Mode 
*/
   ARM_MODE_ABORT = 0x17      /* Abort Processing memory Faults Mode 
*/
   ARM_MODE_UNDEF = 0x1B      /* Undefined Instructions Mode 
*/
   ARM_MODE_SYS   = 0x1F      /* System Running in Priviledged Operating 
Mode */
   ARM_MODE_MASK  = 0x1F

   I_BIT          = 0x80      /* disable IRQ when I bit is set */
   F_BIT          = 0x40      /* disable IRQ when I bit is set */

/*
 * Register Base Address
 */

   .section .vectors,"ax"
   .code 32

/*********************************************************************** 
*****/
/*               Vector table and reset entry 
*/
/*********************************************************************** 
*****/
_vectors:
   ldr pc, ResetAddr    /* Reset                 */
   ldr pc, UndefAddr    /* Undefined instruction */
   ldr pc, SWIAddr      /* Software interrupt    */
   ldr pc, PAbortAddr   /* Prefetch abort        */
   ldr pc, DAbortAddr   /* Data abort            */
   ldr pc, ReservedAddr /* Reserved              */
   ldr pc, [pc, #-0x0FF0]  /* Vector from VicVectAddr */
   ldr pc, FIQAddr      /* FIQ interrupt         */


ResetAddr:     .word ResetHandler
UndefAddr:     .word UndefHandler
SWIAddr:       .word SWIHandler
PAbortAddr:    .word PAbortHandler
DAbortAddr:    .word DAbortHandler
ReservedAddr:  .word 0
IRQAddr:       .word IRQHandler
FIQAddr:       .word FIQHandler

   .ltorg


   .section .init, "ax"
   .code 32

   .global ResetHandler
   .global ExitFunction
   .extern main
/*********************************************************************** 
*****/
/*                           Reset handler 
*/
/*********************************************************************** 
*****/
ResetHandler:
/*
 * Wait for the oscillator is stable
 */
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop

   /*
    * Setup a stack for each mode
    */
   msr   CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT   /* Undefined 
Instruction Mode */
   ldr   sp, =__stack_und_end

   msr   CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT   /* Abort Mode */
   ldr   sp, =__stack_abt_end

   msr   CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT     /* FIQ Mode */
   ldr   sp, =__stack_fiq_end

   msr   CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT     /* IRQ Mode */
   ldr   sp, =__stack_irq_end

   msr   CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT     /* Supervisor Mode */
   ldr   sp, =__stack_svc_end


   /*
    * Clear .bss section
    */
   ldr   r1, =__bss_start
   ldr   r2, =__bss_end
   ldr   r3, =0
bss_clear_loop:
   cmp   r1, r2
   strne r3, [r1], #+4
   bne   bss_clear_loop


   /*
    * Jump to main
    */
   mrs   r0, cpsr
   bic   r0, r0, #I_BIT | F_BIT     /* Enable FIQ and IRQ interrupt */
   msr   cpsr, r0

   mov   r0, #0 /* No arguments */
   mov   r1, #0 /* No arguments */
   ldr   r2, =main
   mov   lr, pc
   bx    r2     /* And jump... */

ExitFunction:
   nop
   nop
   nop
   b ExitFunction


/*********************************************************************** 
*****/
/*                         Default interrupt handler 
*/
/*********************************************************************** 
*****/

UndefHandler:
   b UndefHandler

SWIHandler:
   b SWIHandler

PAbortHandler:
   b PAbortHandler

DAbortHandler:
   b DAbortHandler

IRQHandler:
   b IRQHandler          // wenn ich hier den Namen meiner Routine
                         // reinsetze klappt es mit dem Interrupt

FIQHandler:
   b FIQHandler

   .weak ExitFunction
   .weak UndefHandler, PAbortHandler, DAbortHandler
   .weak IRQHandler, FIQHandler

   .ltorg
/*** EOF ***/

von Jansus (Gast)


Lesenswert?

Ich debugge im RAM. Insofern denke ich es passt schon ;-)

von Andreas K. (a-k)


Lesenswert?

> Wegen der Zählschleife. Sind dafür die paar nops gedacht? Ist das
> überhaupt genug?

Nur wenn es dir gelingt, den Prozessor mit 10Hz zu takten.

von Andreas K. (a-k)


Lesenswert?

> Ich debugge im RAM. Insofern denke ich es passt schon ;-)

Es ist ja nicht so, dass das RAM dann rein garnicht funktioniert. 
Sondern dass es in bestimmten Fällen Mist baut.

Merke: Wer ARM-Controller programmiert und verbaut, ohne vorher das 
dazugehörende Erratasheet gründlich gelesen zu haben, wird mit 
mindestens 3 Jahren PIC16 bestraft! ;-)

EDIT: Das wird sicherlich nichts mit dem Problem hier zu tun haben. Aber 
trotzdem wichtig.

von Andreas K. (a-k)


Lesenswert?

> Ich debugge im RAM. Insofern denke ich es passt schon ;-)

Steht im Flash was drin?

Das läuft nämlich dann so: Nach Reset läuft das Teil erst einmal eine 
Weile aus dem Flash. Dann fängt JTAG ihn ein und schickt ihn ins RAM. 
Wenn der im Flash-Code zu diesem Zeitpunkt schon irgendwas initialisiert 
hat, dann kann das deinen schönen Code höllisch durcheinander bringen.

Einfachste Abhilfe: Für RAM-Debugging einmal vorweg einen Code flashen, 
der rein garnichts tut (Totschleife ab Reset). Oder aber besagte 
Zeitschleife vorneweg hat.

von Jansus (Gast)


Lesenswert?

Ach Du Scheiße!
Habe witzigerweise das Errata gelesen, aber falsch abgeschrieben. Hatte 
MAMTIM=0x04 gesetzt.
Leider hält mich Eclipse gerade und schon seit ner Weile mit 
regelmäßigen Abstürzen vom Testen ab.

von Jansus (Gast)


Lesenswert?

Im Flash ist nix drin.

von Andreas K. (a-k)


Lesenswert?

Diese MAMTIM Initialisierung sollte allerdings vor dem ersten 
RAM-Zugriff passieren. Also direkt nach Reset.

von Jansus (Gast)


Lesenswert?

Ich könnte mir ja so in den Arsch beissen!
Nachdem Eclipse mich jetzt Ewigkeiten vom Ausprobieren abgehalten hat, 
habe ich feststellen müssen, dass es einfach funktioniert!!!
Witzigerweise ist die einzige Änderung das MAMTIM gewesen. Die 
PLL-Feed-Sequenz dauert jetzt zwar irgendwie länger, aber das ist mir 
jetzt mal echt egal!

Auf jedenfall vielen Dank für Eure Tipps und Hilfe!!!!

Den Stack werde ich gleich mal auf 256 stellen.

Ne weitere Frage habe ich allerdings noch. Und zwar, wie mache ich das 
mit der Sicherung der Linkregister? Brauche ich das überhaupt? Möchte 
erstmal dahin kommen, dass ich keine Schwierigkeiten bekomme, wenn der 
Interrupt vom ADC in die Timerinterruptroutine fällt.

von Jansus (Gast)


Lesenswert?

Bisher habe ich noch die PLL-Prozedur davor. Ist besser wenn ich das 
vertausche, oder?

von Andreas K. (a-k)


Lesenswert?

> Ne weitere Frage habe ich allerdings noch. Und zwar, wie mache ich das
> mit der Sicherung der Linkregister? Brauche ich das überhaupt? Möchte
> erstmal dahin kommen, dass ich keine Schwierigkeiten bekomme, wenn der
> Interrupt vom ADC in die Timerinterruptroutine fällt.

Lass das mit dem Nesting sein, bis du ein Stück weiter bist. Die 
Interrupt-Routine läuft von haus aus mit abgeschalteten Interrupts das 
wird dann also nicht passieren.

von Jansus (Gast)


Lesenswert?

Oh, da bin ich beruhigt!
Vielen Dank nochmals!

von Andreas K. (a-k)


Lesenswert?

> Bisher habe ich noch die PLL-Prozedur davor. Ist besser wenn ich das
> vertausche, oder?

Da die Voreinstellung auf "langsamst" steht, ist es eigentlich egal.

So, jetzt ist wieder Doku greifbar. Es geht beim dem Fehler MAM.1 nicht 
um MAMTIM, sondern eher um MAMCR. Und das sollte man vorsorglich gleich 
machen, also bevor man das RAM anfasst, im Startup. Langsameres 
Flash-Timing hingegen sollte erst einmal keine Rolle spielen. Wenn man 
allerdings später am MAMTIM drehen will, sollte man beachten, dass man 
dies lieber nicht bei eingeschaltetem MAM macht.

Das ist nun für deinen RAM-residenten Code nicht von Belang, aber pack 
es lieber trotzdem in den Startup rein. Schadet nicht und erspart Ärger 
später.

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.