Forum: Mikrocontroller und Digitale Elektronik STM32 ASM Interrupt


von STM32 ASM (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe Mikrocontroller Gemeinde.
Ich habe ein kleines Projekt für mich um den STM32F103C8 besser kennen 
zulernen. Ich möchte eine LED blinken lassen und zwar im Takt von einer 
Sekunde. Ich möchte den Takt über Timer 2 realisieren.
Das ganze soll in asm mit keil realisiert werden. LED und PORT alles 
schon richtig Initialisiert der Timer läuft auch schon, aber jetzt kommt 
der Interrupt. Leider habe ich dort keine Idee wie das mit ASM 
realisieren kann.
Ich bin Anfänger in ASM, aber lernwillig. Mir würde es schon reichen 
wenn ich das mit dem NVIC verstehen würde, welche Register für TIM2 
zuständig sind im NVIC.

Ich habe mal mein ASM file mit angehangen. Ich bin auch gerne für 
Verbesserungsvorschläge im Code wie man ihn besser strukturieren kann 
usw.. sehr dankbar.

von derjaeger (Gast)


Lesenswert?

Hallo,

also erstmal empfehle ich dir das:

www.st.com/resource/en/programming_manual/cd00228163.pdf

Im Reference Manual steht das der "TIM2 global Interrupt" die ID 28 hat.

Für die Interruptkonfiguration der Interrupts von 0 bis 31 (dein TIM2 
ist 28) sind die folgenden Register zuständig:


ISER0 (Set-enable): Interrupt aktivieren
ICER0 (Clear-enable): Interrupt  deaktivieren
ISPR0 (Set-pending): Interrupt ausloesen
ICPR0 (Clear-pending): Interrupt Flag loeschen


Du musst das Bit 28 (gezaehlt von 0) ansprechen in ALLEN Registern 
(immer 1 schreiben).

Willst du das TIM2 Interrupt aktivieren dann mach folgendes 
(Pseudocode):


ISER0 |= BIT28



Du musst dann noch die Interrupt global aktivieren per Assemblerbefehl:
"CPSIE I"


So beginnst du deinen Interrupthandler:

.global TIM2_IRQHandler
TIM2_IRQHandler:



Für deinen TIM2 Konfiguration musst du noch folgende Register 
konfigurieren:


TIM2_DIER   Bit UIE

Am besten vor diesem Befehl im Register

TIM2_SR das Bit UIF auf 0 setzen, was du auch am Anfang deines TIM2 IRQ 
Handlers machen solltest.

Ich bin mir nicht sicher, aber es scheint ausreichend nur dieses Flag 
zurücksetzen bei einem Interrupt, dass Register ICPR0 musst du nicht 
ansteuern. Vielleicht mal ausprobieren ob du ein Unterschied zwischen 
ICPR0 und TIM2_SR findest, vielleicht sind diese miteinander verbunden.



Noch ein Tipp:
Folgende PDF Dateien solltest du immer offen haben für deine 
Lernerfolge:

-Datasheet
-Reference Manual
-Programming Manual

Die Informationen sind verteilt über diese 3 Sachen. z.B. habe ich im 
Reference Manual geschaut welche ID dein gewünschter Interrupt hat und 
habe dann im Programming Manual die notwendigen Register identifiziert

von derjaeger (Gast)


Lesenswert?

Ich hab etwas recherchiert:


Wenn der Interrupt aktiviert wird, dann führt der Prozessor automatisch 
ICPR0 aus, aber du musst dich selbst um TIM2_SR kümmern.


Für Interrupt solltest du dir merken:

Es reicht nicht aus die Interrupts für die Peripherie nur zu aktivieren, 
sondern du musst anschließend noch die NVIC Bits dementsprechend setzen 
(meistens Register ISER0)

von STM32 ASM (Gast)


Lesenswert?

Vielen dank für dein ausführliche Hilfe. Genau die drei Sachen habe ich 
auch immer auf. Auf meinem Laptop leider nicht ganz bequem aber so ist 
das halt.
Ich werde das ganze mal ausprobieren. Ich bedanke mich nochmal für die 
Hilfe. Du hast genau das erklärt was ich nicht ganz verstanden hab.

Vielen dank.

von Motze (Gast)


Angehängte Dateien:

Lesenswert?

So gestern noch ein wenig getestet und wie erwartet gibt es noch einige 
Problem. Einige Sachen die ich nicht verstanden habe, habe ich im Code 
kommentiert.
Ich Arbeite auch das erste mal mit "Pusch" und "Pull" befehlen. Die 
scheinen ganz gut zu funktionieren aber muss ich noch einen Stack 
einrichten?

Ich probiere auch gerade eine "If" "Else" Anweisung mit asm 
hinzubekommen.
Bin ich da mit "CMD" auf den richtigen weg?

Mir ist beim lesen von anderen asm Dokumenten aufgefallen das manche 
"befehle" bei mir nicht erkannt werden. Ich nenne mal als Bsp.
.equ geht nicht bei mir aber "Test EQU 0x00000000" wird erkannt. Kann es 
sein das es an .Thump oder ASM liegt und wenn ja welche von beiden 
benutze ich eigentlich?

Ich bedanke mich schon mal.

von Christopher J. (christopher_j23)


Lesenswert?

Motze schrieb:
> .equ

Das kann meines Wissens nach nur der GAS. Keil mag nur EQU.


Motze schrieb:
> Ich probiere auch gerade eine "If" "Else" Anweisung mit asm
> hinzubekommen.
> Bin ich da mit "CMD" auf den richtigen weg?

CMD kenne ich nicht aber CMN und CMP kannst du für Vergleiche nutzen um 
dann darauf folgenden Instruktionen per "condition code" nur unter der 
bestimmten Bedingung auszuführen. Für Sprunganweisungen kannst du CBZ 
("compare and branch if zero") oder CBNZ ("... if non-zero") nutzen.


Wenn du Interrupts nutzen willst benötigst du auch noch eine 
Vektortabelle. Wie diese aussehen kann bzw. sollte, schaust du dir am 
besten im Startup-Code von Keil bzw. ST an, der typischerweise von denen 
für deinen Controller gedacht ist.

von Nop (Gast)


Lesenswert?

Motze schrieb:
> aber muss ich noch einen Stack einrichten?

Die ersten 4 Byte im Flash sind die Stackadresse. Praktisch gesehen 
kannst Du ein uint32_t-Array hernehmen:
uint32_t my_stack[N];

und die Adresse, die dann im Flash am Anfang stehen muß, lautet einfach 
&my_stack[N].

Das ist kein Array-Overflow, weil es sich um einen fully descendent 
stack handelt, d.h. von dem Wert wird vor der Benutzung ERSTMAL 4 
abgezogen und DANN was reingeschrieben, so daß der erste Schreibvorgang 
bei my_stack[N-1] landet, was der letzte Eintrag des Arrays ist.

In Assembler halt entsprechend mit der Reservierung eines entsprechend 
großen Speicherbereiches. Optimal ist, wenn die Adresse &my_stack[N] 
durch 8 teilbar ist.

von Motze (Gast)


Lesenswert?

Danke die Vektortabelle hat Keil schon im Start up fiel erzeugt. Was das
"EXPORT TIM2_IRQHandler" in meinen Code überflüssig macht. Danke für die 
Info.
Jetzt kommt was ganz banales wie kann ich den Inhalt eines Speichers in 
ein Register einlesen?

z.B.

LDR  r5, = GPIOC_ODR  ;Das liest aber nur die Adresse ein
CMP  r5, #0x2000      ;hier möchte ich dann rausfinden ob das Bit 
gesetzt
                         ;ist

Lg Motze

von derjaeger (Gast)


Lesenswert?

Hallo,

was du meinst ist eine indirekte Adressierung (Pointer): Du gibst die 
Adresse in ein Register ein (das ist deine erste Zeile) und dann der 
nachfolgende Befehl:

LDR  r6, [r5] ; Schaue was an der Adresse in R5 steht und lade es in r6



Viele Grüße
derjaeger

von Carl D. (jcw2)


Lesenswert?

derjaeger schrieb:
> Hallo,
>
> was du meinst ist eine indirekte Adressierung (Pointer): Du gibst die
> Adresse in ein Register ein (das ist deine erste Zeile) und dann der
> nachfolgende Befehl:
>
> LDR  r6, [r5] ; Schaue was an der Adresse in R5 steht und lade es in r6
>
>
>
> Viele Grüße
> derjaeger

Und bitte nur die Basisadresse eines Periepherieblocks (z.B.Timer2) in 
r5 laden und die einzelnen Periepherie-Register per
  LDR r5,=Timer2_Base ; eigentlich LDR r5,[pc+n] mit n Offset zur 
Konstante
  LDR r6,[r5+16]      ; Timer2_SR Laden
ansprechen.
Dazu hat Sophie Wilson extra Base-Offset-Adressierung (neben diversem 
Anderem) von den IBM-Mainframes abgeschaut. Das sollte man dann auch 
nutzen.

C-Compiler können das auch, und Hand-Codiert will doch auf keinen Falk 
schlechter sein ;-)

von derjaeger (Gast)


Lesenswert?

>C-Compiler können das auch

Ich hab mir die Defines von der SPL angeschaut und da werden die 
Register so auch definiert: Immer Basisadresse + Offset

von Motze (Gast)


Angehängte Dateien:

Lesenswert?

So schleife läuft keine Ahnung bei mir musste das anstatt CBZ u. CBNZ 
eben BEQ und BNE heißen. Danke für den Hinweis mit LDR r6, [r5] hat mir 
viel weitergeholfen.
So jetzt habe ich nur noch ein Problem mit dem Interrupt,
wenn ich Debugge springt er einmal in den Interrupt und dann nie wieder 
und wenn ich den MCU einfach so laufen lasse scheint der Interrupt aber 
nicht auszulösen.
Ich glaube das ich NVIC noch nicht richtig Konfiguriert habe.

Jetzt muss ich noch lernen wie das ganze hübscher wird und die 
Kommentare was die einzelnen schritte machen, werden immer wichtiger 
habe ich gemerkt.

von Carl D. (jcw2)


Lesenswert?

derjaeger schrieb:
>>C-Compiler können das auch
>
> Ich hab mir die Defines von der SPL angeschaut und da werden die
> Register so auch definiert: Immer Basisadresse + Offset

Nur ist "so auch" nicht das gleiche. Das [rn+ofs] muß schon in einem 
Assembler-Befehl stehen und nicht im "Text-Ersetzungs-Prozessor".

von derjaeger (Gast)


Lesenswert?

Hallo,

der ARM-Mikrocontroller hat ein paar tolle Sachen auf Lager. Eins davon 
sind "conditional executions": Du kannst bei jedem Befehl anhängen WANN 
er eigentlich ausgeführt werden soll.
Dann kannst du dir diese -if-else mit Labels und Jumps sparen:

LDR    r5, = GPIOC_ODR
LDR    r6, [r5]
CMP    r6, #0x2000
;Nur einer von beiden nachfolgenden Befehlen wird ausgefuehrt abhaengig 
vom Ergebnis des CMP
STREQ    r1, [r0];beachte das 'EQ'
STRNE    r2, [r0];beachte das 'NE'

POP    {r1,r2,r3,r4,r5,r6}
BX     LR

Super so ein ARM, oder?

Hier ist eine Liste von Befehlen:
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001m/QRC0001_UAL.pdf

Seite 6, rechte Tabelle: Diese Codes kannst du hinter (fast?) jeden 
Befehl kleben und brauchst gar keine if-else mehr zu machen



Das 'CPSIE    i' gehoert kurz vor deine loop, aber erst NACH dem 
Aktivieren des NVIC Kanals !

Woran dein Interrupt scheitert weiß ich noch nicht.
Ich empfehle dir folgendes zum Suchen:

Ersetze dein Code im Interrupthandler einfach durch folgende Zeile (ohne 
Interruptflag löschen, Push und Pop usw:

LDR    r5, =GPIOC_BSRR ;1 im Register schreiben setzt den Pin
LDR             r6, =0x2000
STR             r6, [r5]
forever:        b forever

Wenn die LED nicht angeht, dann wird dein Interrupt noch nicht 
ausgelöst. Wenn das schonmal klappt, dann funktioniert dein NVIC und der 
Rest sollte einfacher sein

von derjaeger (Gast)


Lesenswert?

Zum Testen würd ich dir empfehlen den obengezeigten Code erstmal in der 
main zu probieren, ob er auch wirklich ausgeführt wird. Dann kannst du 
Sachen wie falsche Portkonfiguration ausschließen und dem Interrupt die 
Schuld in die Schuhe schieben.

Beitrag #5158618 wurde vom Autor gelöscht.
von Motze (Gast)


Angehängte Dateien:

Lesenswert?

Danke für den Hinweis und den sehr guten Link. Die LEDs blinken wie 
gewollt aber leider nur im Debugger.
Der Interrupt wird erreich aber wahrscheinlich nur einmal. Bin mir aber 
nicht sicher. Ich habe das ganze mit deinem Code getestet ohne 
rücksetzen des Interrupt auch leider keine Änderung.
Ich kann im Interrupt die LED ein oder ausschalten, aber nur einmal. 
Entweder ist der Timer 2 nicht richtig Initialisiert so das es ewig 
brauch um ein neuen Interrupt auszulösen oder irgendwas anderes ist es.

Hier ist der aktuelle Code.

von Motze (Gast)


Lesenswert?

Ja und ich finde den ARM super. Ich kratze zwar nur die Oberfläche von 
dem was der alles kann, aber ich bin begeistert. Hatte den vorher immer 
nur in C Programmiert und wollte einfach mehr verstehen was dort vor 
sich geht. Ich merke wie manche Sachen auch Stück für Stück logischer 
erscheinen. Das meine ich in C und ASM.

von derjaeger (Gast)


Lesenswert?

Liegt es vielleicht am Auto reload? Ich habe bei mir damals diese 
Einstellung immer aktiviert für meine Timer:


Register TIM2_CR1:

Bit 7 ARPE: Auto-reload preload enable
0: TIMx_ARR register is not buffered
1: TIMx_ARR register is buffered



Wenn es auch nicht klappt, würde ich dir empfehlen zu schauen ob dein 
Timer sich nicht im Interrupt deaktiviert/stoppt und vielleicht die Bits 
nochmal zu lesen insbesondere das Bit "CEN" und "UIE".

von Christopher J. (christopher_j23)


Lesenswert?

Motze schrieb:
> Ich kann im Interrupt die LED ein oder ausschalten, aber nur einmal.

Wenn ich das richtig sehe liegt das an deiner Toggle-Funktion im 
Handler.

Schau dir nochmal das BSRR im Handbuch an. Das ist kein Toggle-Register. 
Set- und Reset-Bit sind um 16 Bit verschoben und du musst schon das 
jeweils richtige schreiben.

Du musst übrigens nicht alle Register im Handler manuell sichern. R0-R3, 
R12, xPSR, PC und LR landen automatisch auf dem Stack. Darum kümmert 
sich der Prozessor automatisch. Siehe auch 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Babedgea.html

von derjaeger (Gast)


Lesenswert?

>Schau dir nochmal das BSRR im Handbuch an. Das ist kein Toggle-Register.

Er verwendet das Register "ODR" im Interrupthandler (hat er vorher in 
der main ins Register geladen):

This is a 16-bit read/write register. Each bit represents the output 
value on a corresponding pin. Writing a '0' in bit 8 of this GPIOC _ODR 
register indicates that the voltage on PC8 is driven by the micro to 0V 
(GND). While writing a '1' in bit 8 of this GPIOC _ODR register 
indicates that the voltage on PC8 is driven by the micro to 3.3V (VDD).


Was ich im Interrupthandler besser machen würde: Vertraue nicht darauf, 
dass  in r0, r1, r2 bereits das richtige steht (hast du ja in main 
initialisiert) sondern lade es im Interrupthandler nochmal rein. Das 
sieht auch viel lesbarer aus.

von Christopher Johnson (Gast)


Lesenswert?

derjaeger schrieb:
> Er verwendet das Register "ODR" im Interrupthandler (hat er vorher in
> der main ins Register geladen):

Ich hatte nicht gesehen, dass er die vorher korrekt beladen hatte. Der 
von dir vorgeschlagene Code mit BSRR toggelt aber nur einmal, was du ja 
auch gesagt hattest. Ich hatte mich auf das hier bezogen:

> Ich habe das ganze mit deinem Code getestet ohne
> rücksetzen des Interrupt auch leider keine Änderung.
> Ich kann im Interrupt die LED ein oder ausschalten, aber nur einmal.

Beim nochmaligen durchlesen verstehe ich aber selber nicht so ganz, was 
da beim TO jetzt geht und was nicht.


derjaeger schrieb:
> Was ich im Interrupthandler besser machen würde: Vertraue nicht darauf,
> dass  in r0, r1, r2 bereits das richtige steht (hast du ja in main
> initialisiert) sondern lade es im Interrupthandler nochmal rein. Das
> sieht auch viel lesbarer aus.

Das würde ich definitiv auch machen. Wie oben schon geschrieben werden 
r0-r3, etc. ohnehin automatisch gesichert. Die kann man also bedenkenlos 
mit neuen Sachen vollschreiben. Lediglich das Link Register darf man 
nicht (etwa durch ein BL) überschreiben ohne es vorher zu sichern, weil 
da der spezielle Wert "exception return" drin stehen muss. Sonst führt 
ein BX LR logischerweise nicht zum verlassen des Handlers.

von Motze (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

so habe den Code jetzt ein wenig umgeschrieben und euren Tipps 
angepasst. Die Funktion hat das leider nicht verändert. Es wird nur 
einmal in die Interrupt Rutine gesprungen und dann verbleibt das ganze 
in der main Schleife.


Bit 7 ARPE: Auto-reload preload enable <- Habe ich auch umgesetzt hat 
aber leider nicht viel geholfen. Ich habe es aber drin gelassen.

von derjaeger (Gast)


Lesenswert?

Geh nach folgendem Prinzip vor:

Erstmal machst du dein LED blinken mit Timer 2, aber ohne einen 
Interrupt Handler (d.h. UIE = 0), sondern nur in der main nach folgendem 
Schema:


1. GPIO konfigurieren
2. Timer konfigurieren (ohne Interrupt einschalten, UIE = 0)
3. Timer 2 starten (CEN = 1)
4. In einer Schleife das Interrupt Flag von Timer 2 (UIF) abfragen auf 
HIGH
5. Das Interrupt Flag dann löschen wenn UIF = 1
6. Den Pin togglen
7. Springe zurück nach [4] und warte bis der Timer den nächsten 
Interrupt raushaut

Damit testest du ob dein Timer nach einem Interruptauslösung (die du 
aber nicht in einem Interrupthandler bearbeitest sondern in main) weiter 
macht oder keine weiteren Interrupts auslöst nach dem ersten Mal.

von Christopher J. (christopher_j23)


Lesenswert?

Im folgenden Abschnitt triggerst du den Interrupt unabhängig vom Timer, 
quasi per Software. Das würde ich mal rausnehmen und wie es derjaeger 
beschrieben hat schauen ob das Teil jemals im Handler landet.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/Cihjjifh.html
1
    LDR   r0, = NVIC_ISPR0;
2
    LDR    r1, = 0x10000000
3
    STR    r1, [r0]


Im folgenden würde ich unter "B loop" mal ein ENDP packen und ein PROC 
hinter "TIM2_IRQHandler". Es kann sein, das der Linker den Handler an 
eine gerade Adresse packt und dann führt der Sprung in den Handler zum 
Crash. Was sagt eigentlich der Debugger? Für so etwas wurden die doch 
ursprünglich mal entwickelt.
1
    B    loop
2
    
3
TIM2_IRQHandler

von Nop (Gast)


Lesenswert?

Christopher J. schrieb:
> Es kann sein, das der Linker den Handler an
> eine gerade Adresse packt

Tut er sowieso, weil das LSB keine Adreßbedeutung hat, sondern thumb/arm 
auswählt. Bei Cortex-M also immer thumb.

von Christopher J. (christopher_j23)


Lesenswert?

Nop schrieb:
> Christopher J. schrieb:
>> Es kann sein, das der Linker den Handler an
>> eine gerade Adresse packt
>
> Tut er sowieso, weil das LSB keine Adreßbedeutung hat, sondern thumb/arm
> auswählt. Bei Cortex-M also immer thumb.

Ja, für den Cortex-M macht alles außer Thumb-Code keinen Sinn aber das 
heißt nicht, dass er das LSB ignoriert. Auf ein BX zu einer geraden 
Adresse reagiert der Cortex-M allergisch. Das gleiche gilt auch für die 
Sprungadressen in der Vektortabelle. Das hatten wir letztens erst:
Beitrag "STM32F401 C-ISR durch Assembler-ISR ersetzen"

von Motze (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank an alle Unterstützer.
Jetzt Funktioniert alles und der Timer2 löst im Sekundentakt sein 
Interrupt aus.

LDR    r0, = TIM2_DIER
MOV    r1, #1
STR    r1, [r0]

Das hat gefehlt. Manchmal kann so ein paar Zeilen Code mehrere Stunden 
Arbeit bedeuten. So jetzt kommt mein nächstes Projekt und das soll eine
7 Segment Anzeige in Sekundentakt hochzählen lassen.

Ich bedanke mich nochmal an die Unterstützer und habe den vollständigen 
Code angehangen.

von Nop (Gast)


Lesenswert?

Christopher J. schrieb:
> Auf ein BX zu einer geraden
> Adresse reagiert der Cortex-M allergisch.

Ja, weil "gerade Adresse" soviel bedeutet wie "mach am Ziel mal mit 
ARM-Code weiter", und Cortex-M kann nur Thumb. Logisch stürzt das ab.

Trotzdem ist die Funktion physikalisch an einer geraden Adresse richtig, 
auch wenn in der Vektortabelle die Sprunganweisung zu einer ungeraden 
geht. Das heißt soviel wie "spring zu der geraden Adresse und ignoriere 
das LSB dabei, aber mach mit Thumb weiter".

Um das überhaupt machen zu können, muß das LSB für die Anzeige des 
Codemodus der Zielfunktion reserviert sein, und das bedeutet, daß die 
Funktionen physikalisch immer an geraden Adressen liegen, also was den 
Linker angeht. Der linkt das nicht an ungerade Adressen, sondern das 
geht andersrum, daß zu den Sprunganweisungen 1 draufaddiert wird.

von Mampf unterwegs (Gast)


Lesenswert?

STM32 ASM schrieb im Beitrag #5157176:
> Leider habe ich dort keine Idee wie das mit ASM realisieren kann.
> Ich bin Anfänger in ASM, aber lernwillig.

würde ich bleiben lassen ... Assembler macht auf solchen Geschossen 
keinen Sinn mehr ... und der Compiler optimiert eh besser, als es jemand 
per Hand machen könnte :)

von Carl D. (jcw2)


Lesenswert?

Mampf unterwegs schrieb:
> STM32 ASM schrieb im Beitrag #5157176:
>> Leider habe ich dort keine Idee wie das mit ASM realisieren kann.
>> Ich bin Anfänger in ASM, aber lernwillig.
>
> würde ich bleiben lassen ... Assembler macht auf solchen Geschossen
> keinen Sinn mehr ... und der Compiler optimiert eh besser, als es jemand
> per Hand machen könnte :)

Besonders wenn man sieht mit welchem Aufwand beim Togglen das XOR 
realisiert ist. Conditional Move ist "cool", aber nicht immer 
angebracht.

von Christopher J. (christopher_j23)


Lesenswert?

Nop schrieb:
> Trotzdem ist die Funktion physikalisch an einer geraden Adresse richtig,
> auch wenn in der Vektortabelle die Sprunganweisung zu einer ungeraden
> geht. Das heißt soviel wie "spring zu der geraden Adresse und ignoriere
> das LSB dabei, aber mach mit Thumb weiter".

Da hast du natürlich vollkommen Recht. Ich meinte auch die Adresse in 
der Vektortabelle aber habe mich falsch ausgedrückt.


Motze schrieb:
> LDR    r0, = TIM2_DIER
> MOV    r1, #1
> STR    r1, [r0]

Das hattest du vorher auch schon mit drin und jetzt eben zweimal. Ich 
glaube nicht das es daran lag.

von derjaeger (Gast)


Lesenswert?

Ich konnte auch nichts großartiges unterschiedliches feststellen außer 
das nach dem loop in der main ein "ENDP" hinzugefügt wurde. Und 
natürlich das in der IRQ das Flag am Anfang zurückgesetzt wird.
1
    
2
;Timer 2 bei NVIC
3
LDR   r0, = NVIC_ISPR0;
4
LDR    r1, = 0x10000000
5
STR    r1, [r0]

Diese Stelle ist immer noch unnötig im Code, damit löst du einen 
Interrupt selbst aus bzw. diese Codestelle hat dort nichts zu suchen.

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.