Ich habe einen LPC2294 und möchte, dass alle 0.5s der Timer resettet wird und eine ISR ausgelöst wird. Dazu habe ich den Timer0 wie folgt initialisiert: T0PR = 0x0; //Prescale Register (Überlaufwert) 0 => pclk = 58.9824MHz = Timer-Clock T0MCR = 0x3; //TimerCounter = MatchRegister0 => Interrupt 0 + Timer Counter Reset T0MR0=58982400; //MatchRegister0 entspricht 0.5s T0TCR=0x2; //Prescale-Counter und Timer-Counter werden resettet T0TCR=0x1; //Prescale-Counter und Timer-Counter werden gestartet Der Timer zählt also 0.5 Sekunden hoch, löst dann den Interrupt aus und wird resettet. Das funktioniert so auch. Den VIC hab ich wie folgt konfiguriert: #define VIC_Timer0 4 VICIntEnClr = 0xFFFFFFFF; VICIntEnable = 1<<VIC_Timer0; VICIntSelect = 0x00000000; VICVectCntl0 = 0x24; VICVectAddr0 = (unsigned long)IRQ_Timer0; Die ISR-Routine ist wie folgt deklariert/definiert: void _attribute_ ((interrupt("IRQ"))) IRQ_Timer0 (void); void IRQ_Timer0 (void){ switchLED(); // Methode zum toggeln der LED T0IR = 0x01; // Rücksetzen des Timerinterrupts VICVectAddr = 0; // Acknowledge Interrupt } Das Problem ist, dass die ISR scheinbar nicht ausgelöst wird. Ich habe dazu nun im Datenblatt, im Forum und auch bei Google versucht das Problem zu lösen, hab auch Ansätze entdeckt aber nicht ganz verstanden. Im ARM-Elf-Gcc-Tutorial stand folgendes: Falls die Interrupts nicht funktionieren, hilft ein Blick in die Startup-Datei. Es müssen einige Vorbereitungen getroffen werden, damit Interrupts aus C heraus funktionieren können. Einen passenden Startup-Code gibt es bei den WinARM-Beispielen mit IRQ-Beispielen. In einem andern Thread mit ähnlichem Problem fand ich folgendes: ...ich hatte lediglich vergessen in der Preprozessor Anweisung VECTORED_IRQ_INTERRUPTS einzutragen. Nunja ich bin überfordert mit dem Problem und habe nun 2 Tage lang auf eigene Faust und mit Hilfe von Tutorials, Datenblättern und andern Threads das Problem zu lösen versucht. Ohne Erfolg leider. Für Hilfe wäre ich also sehr dankbar, wenn weitere Angaben nötig sind werde ich diese natürlich nachreichen.
Benutzt du denn eines der Beispiele aus WinARM? Im Startupcode muß bei einem Interrupt die Adresse der ISR vom VIC gelesen und danach angesprungen werden. Wenn du einen generischen ARM Code dazu hast wird das vermutlich nicht gemacht. Schau doch mal nach ob du folgendes in der .S Datei findest. Es geht um die vorletzte Zeile.
1 | // Runtime Interrupt Vectors
|
2 | // -------------------------
|
3 | Vectors: |
4 | b _start // reset - _start |
5 | ldr pc,_undf // undefined - _undf |
6 | ldr pc,_swi // SWI - _swi |
7 | ldr pc,_pabt // program abort - _pabt |
8 | ldr pc,_dabt // data abort - _dabt |
9 | nop // reserved |
10 | ldr pc,[pc,#-0xFF0] // IRQ - read the VIC |
11 | ldr pc,_fiq // FIQ - _fiq |
Wenn du das ganze Projekt anhängst, könnte ich mal versuchen das hier auf einem 2148 zum Laufen zu bringen.
Ich habe mir da Beispiele angeschaut aber nicht direkt benutzt. Mein Projekt ist eins das ich mal wo gefunden hab, aber mittlerweile total verändert. Ich hatte Startschwierigkeiten, da ich mich weder in Assembler noch mit Makefiles besonders auskenne. Wollte mich qasui aufs C-Programmieren konzentrieren. Was ich jedoch erkenne ist das in dem src-Ordner eine Assembler-Datei ist die auch in der Makefile weiter verwendet wird... Wozu brauch ich in Assembler diesen Verweis auf die Adresse auf die gesprungen wird, ich dachte dazu wäre die Zeile VICVectAddr0 = (unsigned long)IRQ_Timer0; da. Ist es wirklich nicht möglich ohne Assembler auszukommen?
In deiner Zuweisung speicherst du die Adresse der ISR in einem der VIC Register. Wenn ein Interrupt auftritt meldet der VIC das dem ARM7 und dieser holt sich dann die ISR Adresse vom VIC. Ich wüßte nicht wie man das ohne Assembler machen sollte. Für jede ARM7 Reihe der verschiedenen Hersteller brauchst du aber nur jeweils eine Assemblerdatei. Bei NXP sind das zwei: Die LPC21xx/22xx und die LPC23xx/24xx. Die kannst du dann von Projekt zu Projekt unverändert übernehmen. Ich sehe mir das Projekt heute Nachmittag mal an.
Was mir aufgefallen ist, ohne wirklich genau analysiert zu haben: - IRQs sind im Ausführungsmodus der Anwendung nach dem Startup (crt.s) nicht freigegeben. Habe auch keine spätere Freigabe im Code gesehen. Testweise | IBIT | F_BIT bei in msr CPSR_c, #ARM_MODE_SVC entfernen. - IRQ Vector zeigt auf Assembler-"Funktion" IRQ_Handler mit Endlosschleife. Sehe im restlichen Code keine Funktion, die diese "weak"-Funktion mit einem brauchbaren IRQ-Handler überschreibt. Alternativ wie von let beschrieben beim IRQ-Vector direkt die VIC-Vector-Addresse in den Programm-Counter laden. - Code soll wohl zur Ausführung aus dem RAM gelinkt werden. Damit der ARM-Core die Interrupt-Vektoren (inkl. dem für IRQ) an der richtigen Stelle (also im RAM) findet, ist ein re-mapping erforderlich. Vgl. Erläuterungen rund um MEMMAP im Manual.
Hm ich hatte gedacht ich speichere in dem VIC Register die Adresse an der sich die ISR befindet, so dass der ARM im Falle des Auslösens des Interrupts an diese springen kann. Ich habe leider so gar kein Verständnis von Assembler und bin ohne auch bisher immer gut ausgekommen. Aber ich füchte bei den ARMs ist das alles nicht so komfortabel wie bei den AVRs mit AVRStudio...um Makefiles muss ich mich ja auch von Hand kümmern und so...
Steffen Krebs wrote: > Ich habe leider so gar kein Verständnis von Assembler und bin ohne auch > bisher immer gut ausgekommen. Dann empfehle ich eine Entwicklungsumgebung, die alle solchen Startup-Probleme für die gewünschten Controller fertig und dokumentiert mitliefert. Bei WinARM gilt das leider nicht. Da gibt es zwar manchen Sample-Code, aber ohne Einblick in Assembler steht man trotzdem schnell im Nebel.
Ich benutze zur Zeit Eclipse mit Yagarto...was wäre denn dann eher für mich zu empfehlen? Sowas "Komplettes" wie AVRStudio gibt es meines Wissens für ARM-Controller leider nicht...
Was deinen Code angeht: Mit diesem Startup-Code musst du eine Interrupt-Funktion mit dem festgelegten Namen "IRQHandler" definieren, sonst läuft ein Interrupt sofort in eine Totschleife und das war's. Diese Funktion darf dann den VIC fragen wie denn der Vektor lautet und das aufrufen. Und wie Martin schon sagte: Für Einsatz im Flash taugt er nicht, weil die Initialisierung von initialisierten Daten fehlt.
Steffen Krebs wrote: > Sowas "Komplettes" wie AVRStudio gibt es meines > Wissens für ARM-Controller leider nicht... Doch natürlich, nur nicht so billig. Hier im Forum wurde schon öfter mal http://www.rowley.co.uk/arm/ genannt, ich kenne es aber nicht selbst. Ist immerhin noch bezahlbar. Das hat auch was damit zu tun, dass das AVR Studio vom Hersteller der AVRs stammt und das WinAVR Paket m.W. von einem Atmel Mitarbeiter gepflegt wird. ARMs gibt es wie Sand am Meer von Dutzenden verschiedener Hersteller und mit etlichen unterschiedlichen Eigenheiten die im Startup-Code berücksichtigt werden müssen. Und es gibt halt niemanden, der das alles einsammelt und für Lau pflegt.
So, fertig. Es fehlte eigentlich nur die besagte Zugriff auf das VIC Register im Startcode und ich habe einen Sprung auf die Reset-Routine am Anfang des Interruptvektors hinzugefügt. Aus irgendeinem Grund funktioniert bei mir das Auslesen des IO0PIN Registers nicht. Für den LED Port lese ich immer eine 0. Daher habe ich eine Toggle-Variable im Handler benutzt. Getestet habe ich das auf einer Steuerplatine für eine elekronische Morsetaste mit einem LPC2136/01. Das 2148 Board funktioniert irgendwie nicht mehr. Zumindest kann ich da mit FlashMagic nichts machen. Ich habe jedenfalls den Code mit der ROM-Version des Linkerscripts gelinkt und ins Flash gespielt. Das Makefile im Anhang verweist aber wieder auf die RAM-Version. Ob das funktioniert habe ich nicht probiert. Das ganze Beispiel ist für meinen Geschmack etwas zu einfach gehalten. Darauf aufzubauen halte ich für keine gute Idee. Auf der WinARM Seite von Martin Thomas findest du etwas vollständigere Programme. Die Beispiele für die LPC21xx Reihe sollten auch auf deinem 2294 laufen. Du mußt dir nur die Ports ansehen und die Quarzfrequenz beachten.
Danke erstmal. Ich versuche das nun erstmal nachzuvollziehen alles. An der C-Datei hast du also die switchLED-Funktion geändert, aber nur weil sie bei dir nicht funktioniert hat. Wozu ist die volatile unsigned "counter" da? Sonst erkenne ich keine Veränderungen in dieser Datei. Dieser Startcode von dem du redest, ist das die Datei crt.s? Diese Datei soll ich also in jedes Projekt einbinden so wie du sie mir jetzt geschickt hast und der Assembler-Teil ist totgeschlagen? Welchen Teil hast du dort genau hinzugefügt? Wenn ichs richtig verstanden hab hast du das Makefile nur für dich verändert um das Programm in den Flash zu speichern richtig? Ich benutze hier einen ARM-USB-OCD Jtag Adapter von daher schreibe ihn ihn in den RAM... Nun zum Resultat: Die LED toggelt tatsächlich jetzt, die ISR wird also scheinbar aufgerufen. Das Problem ist, dass wenn immer sie toggelt unter "disassembly" ein Breakpoint auftaucht und das Programm anhält. Entferne ich diese Breakpoints toggelt die LED nicht mehr...was könnte das nun wieder sein? Wenn ich das Makefile wieder auf ROM umschreibe und das Programm in den Flash schreibe, geht die LED einmal an und toggelt gar nicht mehr...:-/ Bisschen viele Fragen auf einmal, fürchte ich, aber icrgendwie muss ich mich ja durchbeißen :-/ Auf jeden Fall Danke für jede Art von Hilfe!
Darauf was da auf deinem Board passiert kann ich mir auch keinen Reim bilden. Ich habe mal ein anderes Projekt zusammenkopiert. Es verwendet eine andere crt.S und auch ein anderes Linkerscript. Dieser Startcode initialisiert auch Variablen aus dem Flash. Damit müßtest du eigentlich klarkommen solange du Dateien die ISRs enthalten nicht im Thumb-Mode übersetzt. Da hat der gcc einen Bug und erzeugt falschen Code. Die irq.h enthält eigenen entry-/exit- code für den Thumb-Mode. Ob das funktioniert kann ich dir aber nicht sagen. Wenn es nicht geht, du aber mit dieser Einschränkung leben kannst, brauchst du eigentlich keine andere Assemblerdatei für die LPC21xx/22xx Reihe. In dieser Datei werden allerdings die Stackgrößen festgelegt, sodaß du da vielleicht doch noch mal editieren mußt. Die Hardware wird in sysconf.h konfiguriert. Mein Testboard hier hat einen 12MHz Quarz, eingestellt ist das Beispiel auf deinen 14.745MHZ Quarz. So ganz fertig ist das allerdings nicht. Doch ich denke es ist eine Basis mit der du vielleicht etwas anfangen kannst. Den RAM-Mode habe ich nicht getestet, das Projekt ist für Flash eingestellt.
Ich sollte vielleicht noch erwähnen das der meiste Code von der WinARM Seite stammt. Es ist eine Zusammenstellung aus mehreren Beispielen und einer Handvoll eigener Zeilen.
Hm vor Kurzem dachte ich noch ich komm langsam klar mit dem Lpc...die ersten Programme liefen, BlinkLED mit Timer, AD-Wandler, LCD, das Übliche halt... Aber jetzt bin ich grad wieder total überfordert... Aaalso: Wenn ich das richtig verstanden habe ist dieser Startup-Code derjenige der aufgerufen wird wenn der Controller aus dem Reset kommt, richtig? Warum muss er unbedingt in Assembler geschrieben sein? Mein Problem ist dass ich diese Datei 0 verstehe...und ich habe auch schon versucht verschiedene Startup Dateien in mein Projekt einzubinden...mal passiert gar nichts, mal meckert der Gnu Compiler...im Prinzip ist es wildes, konzeptloses Ausprobieren meinerseits... Dann das nächste Problem, den ich als Rechnerarchitektur umfassen würde. Davon weiß ich auch nicht das meiste...es gibt ARM- und THUMB-Instruktionen...was das genau bedeutet, wo der Unterschied liegt usw. ist mir nicht bekannt... Und soviel ich auch lese, im Insider's Guide, bie WinARM, im Forum usw. ich glaube jede beantwortete Frage wirft 2 neue auf, es ist wie die Nadel im Heuhaufen suchen... Beim AVR war das alles wesentlich einfacher alles... Versteht ihr im Detail was in der crt.s steht, wie der ARM7 funktioniert, das Makefile und die linker-Datei und alles? Wie lang habt ihr dafür gebraucht, wenn man fragen darf?
@let Du hast beim Projekt mcn_rev1 einfach nur die crt.s verändert, das makefile angepasst um in den Flash zu schreiben und die main so verändert dass sie auch bei dir läuft richtig? und das resultat war, dass die LED alle 0.5 Sekunden getoggelt ist?
Ich habe nun verschiedene Startup-Dateien versucht einzubinden, von WinARM, von Olimex usw. es gibt eigentlich immer Fehler beim build Project, beispielsweise diesen hier bei der Benutzung der Startup-Datei aus einem Olimex-Projekt speziell für den lpc2294... Weiß jemand Rat? c:/programme/yagarto/bin/../lib/gcc/arm-elf/4.2.2/../../../../arm-elf/bi n/ld.exe: warning: cannot find entry symbol ResetHandler; defaulting to 40000000 ./src/crt.o: In function `Undef_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `UNDEF_Routine' ./src/crt.o: In function `SWI_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `SWI_Routine' ./src/crt.o: In function `PAbt_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `UNDEF_Routine' ./src/crt.o: In function `DAbt_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `UNDEF_Routine' ./src/crt.o: In function `IRQ_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `IRQ_Routine' ./src/crt.o: In function `FIQ_Addr': C:\Projekte\workspace\mcn/src/crt.s:51: undefined reference to `FIQ_Routine' ./src/crt.o: In function `Reset_Handler': C:\Projekte\workspace\mcn/src/crt.s:107: undefined reference to `_stack_end' C:\Projekte\workspace\mcn/src/crt.s:107: undefined reference to `_etext' C:\Projekte\workspace\mcn/src/crt.s:107: undefined reference to `_data' C:\Projekte\workspace\mcn/src/crt.s:107: undefined reference to `_bss_start' C:\Projekte\workspace\mcn/src/crt.s:107: undefined reference to `_bss_end' collect2: ld returned 1 exit status make: *** [test.elf] Error 1
>Du hast beim Projekt mcn_rev1 einfach nur die crt.s verändert, das >makefile angepasst um in den Flash zu schreiben und die main so >verändert dass sie auch bei dir läuft richtig? und das resultat war, >dass die LED alle 0.5 Sekunden getoggelt ist? Genau. Allerdings verwende ich hier auch noch einen anderen Compiler (CodeSourcery light). Das sollte aber keinen Unterschied machen, der heißt einfach nur anders (arm-none-eabi-gcc). Es scheint so das IOxPIN bzw. IOPINx nur den Zustand von jenen Pins zurückgibt die als Eingang konfiguriert sind. Beim LPC23xx geht das bei jedem Pin. Da habe ich ein TOGGLEPIN Makro geschrieben das mit IOPIN arbeitet. Komisch nur das ich darüber im Datenblatt nichts finde. Bei deinem crt.S Problem liegen vermutlich zwei Fehler vor: - Die xxx_Addr Funktionen müssen wohl noch implementiert werden. Es scheint sich um ein Template zu handeln. - Die Symbole _data, _etext usw. werden im Linkerscript definiert und sind Platzhalter für Adressen. Startupdatei und Linkerscript müssen zueinander passen. Die Startcode/Interrupt Geschichte ist das größte Problem beim Einstieg in die ARM7 Welt. Danach wird es leichter. Der ARM7 ist halt als Mikroprozessor entworfen worden und er hat keinen Interruptcontroller. Da jeder Hersteller hier (notgedrungen) sein eigenes Süppchen kocht gibt es keinen einheitlichen Startcode. Beim Cortex M3, dem Nachfolger des ARM7 für Mikrocontroller hat sich einiges geändert. Der kommt mit einem intregrierten Interrupt- controller und macht beim ISR-Handling einiges in Hardware. Einen Startcode braucht der zwar auch (wie der AVR), da der aber immer gleich aussieht ist der bereits in den Bibliotheken enthalten. Der Anwender merkt davon gar nichts. Ein Linkerscript braucht man soweit ich weiß dennoch. > ARM...Thumb... Bist du dir sicher das du den Insider Guide gelsen hast? ;) Das sind die beiden Befehlssätze des ARM7. Normalerweise wird ARM Code ausgeführt. Da aber durch die 32Bit breiten Befehle der Code schnell ziemlich groß werden kann hat ARM irgendwann einen 16Bit Befehlssatz nachgerüstet. Der resultierende Code ist etwas kompakter (~30%), oft aber auch langsamer. Ein weiterer Vorteil ist das externer Programmspeicher mit 16Bit angebunden werden kann ohne das gleich zwei Speicherzugriffe pro Befehl erfolgen müssen. Läuft denn das andere Beispiel (rev2) bei dir?
Hallo Steffen, mit diesen Problemen hatte ich anfangs auch zu kämpfen mit einer Freeware Version von WinARM. Probleme, die mit dem internen Verständnis zu tun haben aber nichts mit Deinem Problem. Und eine derart komplexe RISC CPU intern verstehen zu wollen, dazu gehört schon jede Menge Schmerzfreiheit. Zunächst habe ich mir eine sagen wir mal .... freigeschaltete Version von Rowley Crossworks besorgt, zwei Wochen später dann für 75 Pfund sie gekauft. Das ist der Studentenpreis ohne Limitierung. Mit der Oberfläche kann man nach ein paar Tagen sicher umgehen, man klickt nur an was man will: Debuggen im Ram, Release Version, aus dem RAM heraus starten usw und der Compiler kümmert sich um die Kopierroutinen, Einsprünge usw. Die Oberfläche lässt sich für eine Unzahl CPU's seinsetzen, für fast alle hat die Libraries dabei. Die Doku ist vorbildlich auf der Homepage. Die Umgebung hat für jeden ARM die passende Startup Umgebung und eine sehr komfortable Linker Konfiguration, kein Makefile, einfach nichts. Das erzeugt die Oberfläche automatisch, die mit dem GNU CC zusammenarbeitet. Investier das Geld oder lade Dir mal die Testversion runter, es lohnt sich allemale. Christian Hier mein Code für zwei blinkende LEDs:
1 | oid InitSystem(char PLL) |
2 | {
|
3 | // Fast GPIO Register Maske setzen, nur angeschlossene Pins aktivieren
|
4 | FIO0MASK = ~(LED_GRN_MASK | LED_ROT_MASK); |
5 | |
6 | if (PLL) |
7 | {
|
8 | |
9 | // PLL einstellen....
|
10 | // MSEL setzen......
|
11 | PLLCFG = PLLCFG & ~(PLLSTAT_MSEL4_0_MASK); |
12 | PLLCFG = PLLCFG | ((PLL_M-1)<<PLLSTAT_MSEL4_0_BIT); |
13 | |
14 | // PSEL setzen....
|
15 | PLLCFG = PLLCFG & ~(PLLSTAT_PSEL1_0_MASK); |
16 | PLLCFG = PLLCFG | ((PLL_P-1)<<PLLSTAT_PSEL1_0_BIT); |
17 | |
18 | // PLL aktivieren aber noch nicht connekten
|
19 | PLLCON = 0x01; // Enable |
20 | |
21 | // PLL Feed-Sequenz schreibt Werte ein, muss als letztes kommen
|
22 | PLLFEED = 0xAA; |
23 | PLLFEED = 0x55; |
24 | |
25 | while (!(PLLSTAT & PLLSTAT_PLOCK_MASK )); // Darauf warten, dass die Änderungen übernommen werden |
26 | |
27 | /*
|
28 | Mit MAMTIM werden die Waitstates beim Flashspeicherzugriff eingestellt, das Datenblatt empfiehlt:
|
29 | 1 - bei unter 20 Mhz, 2 - bei 20-40 Mhz , 3 - bei über 40 Mhz
|
30 | */
|
31 | |
32 | MAMTIM = 3; // 3 Wait States für > 40 Mhz |
33 | MAMCR = 2; // Memory Manager voll aktivieren |
34 | |
35 | // PLL mit Taktgeber verbinden
|
36 | PLLCON = 0x03; |
37 | PLLFEED = 0xAA; // PLL Feed Sequence |
38 | PLLFEED = 0x55; |
39 | |
40 | }
|
1 | // Ruft einen IRQ alle Millisekunden auf
|
2 | void InitTimer0(unsigned int millisec) |
3 | {
|
4 | #define TIMER0_IRQ 4
|
5 | #define TIMER1_IRQ 5
|
6 | |
7 | // Timer 0 ist ein IRQ interrupt
|
8 | VICIntSelect&= ~(1<<TIMER0_IRQ); |
9 | // Benutze slot 0 für timer 0 interrupt, Bit 5 = 1 => Slot aktivieren
|
10 | VICVectCntl0=(1<<5) | TIMER0_IRQ; |
11 | // Enable timer 0 interrupt
|
12 | VICIntEnable = (1<<TIMER0_IRQ); |
13 | // Setze die Adresse der ISR für slot 0
|
14 | VICVectAddr0 = (unsigned int)timer0ISR; |
15 | |
16 | // Setze Timermatch 0 auf 1 Millisekunde
|
17 | T0MR0 = PLL_GetAPBClock()/1000; |
18 | // Setze den Timer 0 prescale counter auf den Wert der Parameterliste
|
19 | T0PR = millisec; |
20 | // Reset timer 0
|
21 | T0TCR = 0; |
22 | // Match = IRQ auslösen und Timer resetten
|
23 | T0MCR |= T0MCR_Interrupt_on_MR0_MASK | T0MCR_Reset_on_MR0_MASK; |
24 | // Start timer 0
|
25 | T0TCR = T0TCR_Counter_Enable_MASK; |
26 | |
27 | // ---------- Timer 1 setzen ----------------
|
28 | |
29 | // Timer 1 interrupt is an IRQ interrupt
|
30 | VICIntSelect&= ~(1<<TIMER1_IRQ); |
31 | // Enable timer 1 interrupt
|
32 | VICIntEnable = 0x20; |
33 | // Use slot 1 for timer 1 interrupt, Bit 5 = 1 => Slot aktivieren
|
34 | VICVectCntl1=(1<<5) | TIMER1_IRQ; |
35 | // Set the address of ISR for slot 1
|
36 | VICVectAddr1 = (unsigned int)timer1ISR; |
37 | |
38 | // Reset timer 1
|
39 | T1TCR = 0; |
40 | // Set the timer 1 prescale counter
|
41 | T1PR = 5000; |
42 | // Set timer 1 match register
|
43 | T1MR0 = 5000; |
44 | // Generate interrupt and reset counter on match
|
45 | T1MCR = 3; |
46 | // Start timer 1
|
47 | T1TCR = 1; |
48 | |
49 | |
50 | // Enable Interrupts
|
51 | __ARMLIB_enableIRQ(); |
52 | }
|
53 | |
54 | //////////////////////////////////////////////////////////////////////////////
|
55 | // Die ISR des Timers 0
|
56 | //////////////////////////////////////////////////////////////////////////////
|
57 | |
58 | static void timer0ISR(void) |
59 | {
|
60 | static unsigned char counter; |
61 | |
62 | // LEDs umschalten
|
63 | if (++counter %2 ==0) |
64 | FIO0CLR = LED_GRN_MASK; |
65 | else
|
66 | FIO0SET = LED_GRN_MASK; |
67 | |
68 | // Weitere IRQ Aktionen....
|
69 | |
70 | |
71 | // IR Flag des M0 Match Registers löschen (=setzen)
|
72 | T0IR |= T0IR_MR0_MASK; |
73 | |
74 | VICVectAddr = 0; // Acknowledge Interrupt |
75 | }
|
76 | |
77 | //////////////////////////////////////////////////////////////////////////////
|
78 | // Die ISR des Timers 1
|
79 | //////////////////////////////////////////////////////////////////////////////
|
80 | |
81 | static void timer1ISR(void) |
82 | {
|
83 | static unsigned char counter; |
84 | |
85 | // LEDs umschalten
|
86 | if (++counter %2 ==0) |
87 | FIO0CLR = LED_ROT_MASK; |
88 | else
|
89 | FIO0SET = LED_ROT_MASK; |
90 | |
91 | |
92 | // Clear the timer 1 interrupt
|
93 | T1IR |= T1IR_MR0_MASK; |
94 | |
95 | // Update VIC priorities
|
96 | VICVectAddr = 0; |
97 | }
|
@let Die SwitchLED-Funktion mit dem Auslesen der Ausgänge über IOPIN funktiniert in dem Vorgänger-Programm bei mir jedenfalls. Dort lese ich den T0IR mit ner if-Abfrage in der while-Schleife aus. Funktioniert alles wunderbar, nur möchte ich das jetz mit dem VIC realisieren, was ja eigentlich Sinn der Sache ist. Das mcn_rev2 - Beispiel lässt sich kompilieren, wenn ich dann jedoch mittels Flashmagic die hex-Datei in den Controller schicke und das Programm starte passiert gar nichts. die crt.s-Dateien in Kombination mit den linkerskripten in mein Projekt einzubinden funktioniert. Zumindest das Kompilieren klappt. Allerdings führt es bei Programmausführung auch nicht zum gewünschten Ergebnis... :-( Allerdings ist es vermutlich auch nicht Sinn der Sache irgendne Startup Datei mit dem passenden Linkerskript aus nem andern Projekt ohne Sinn und Verstand rauszukopieren...vermutlich sind die Linkerskripte mindestens an den Controllertyp angepasst, wenn nicht sogar an das Projekt, oder?
@Christian das mit dem Rowley klingt in der Tat nach genau dem was ich suche...muss ich mal sehen ob das evtl. weiter hilft.
Es hilft :-) 1996 bestand das Windows 3.11 Programm "Hello World" aus 100 Zeilen Code: 99 Zeilen für die interne Steuerung von Windows, die nur eingeweihten Gurus verständlich war und einer Zeile "Hello World". 2008 besteht es aus der einen Zeile "Hello World", den Rest übernimmt die Oberfläche, die die komplexen Vorgänge in den Registern der CPU auf ein dem Menschen erträgliches Maß reduziert, denn nicht nur ich bin der Ansicht, dass sich die Rechenmaschine uns anzupassen hat und nicht umgekehrt, sie ist Mittel um ein Ziel zuereichen aber kein Selbstzweck. Es sei denn Du willst vor einer Tastatur sitzen, die nur 0,1 und Return hat, wodurch sich der echte Programmierer absetzt :-) Der Overhead spielt keine Rolle mehr, wenn die Effizienz der Arbeit dadurch um das 10-fache ansteigt und das gehuddel mit Linkerskripten aufhört, eine Arbeit die die das GUI der Oberfläche abnimmt und ein Skript erzeugt. >>Aaalso: Wenn ich das richtig verstanden habe ist dieser Startup-Code >>derjenige der aufgerufen wird wenn der Controller aus dem Reset kommt, >>richtig? Warum muss er unbedingt in Assembler geschrieben sein? Um maximale Effizienz zu erreichen, ausserdem ist der Platz begrenzt da vorne im ARM7 bei Adresse 0x0000000. RISC Assembler hat allerdings etwas mit dem Gestammel eines Babys gemeinsam, mit wenigen Worten viel ausdrücken zu müssen, daher nicht ganz einfach zu verstehen. >>void IRQ_Timer0 (void){ >> switchLED(); // Methode zum toggeln der LED >> T0IR = 0x01; // Rücksetzen des Timerinterrupts >> VICVectAddr = 0; // Acknowledge Interrupt >>} Hier kann es zu Problemen führen, da die Funktion swicthled ausserhalb liegt. Bei mir zumindest führte es dazu. Die Ursache wüsste ich auch gerne. Seit ich die Funktion #inline habe geht es. Viel Spass !
>Die SwitchLED-Funktion mit dem Auslesen der Ausgänge über IOPIN >funktiniert in dem Vorgänger-Programm bei mir jedenfalls. So würde ich das auch erwarten. Es ist mir ein Rätsel warum das bei mir mit dem 2136/01 nicht funktioniert. Aber egal, ich verwende ohnehin nur noch den 23xx und schiele auf den STM32 um den 8Bittern endgültig zu entsagen (NXP hat den Bereich ja der Konkurrenz überlassen). >Allerdings ist es vermutlich auch nicht Sinn der Sache irgendne Startup >Datei mit dem passenden Linkerskript aus nem andern Projekt ohne Sinn >und Verstand rauszukopieren...vermutlich sind die Linkerskripte >mindestens an den Controllertyp angepasst, wenn nicht sogar an das >Projekt, oder? Die CRT muß nur dann verändert werden wenn die Funktionalität nicht ausreicht. Die Variante der rev2 sollte für die meisten Anwendungen geeignet sein. Was dort fehlt ist die Unterstützung für C++. Das Interrupt Handling verläßt sich auf funktionierende Compiler bzw. auf inline-asm in den ISRs. Die einzige Stellschraube dort ist die Stack-Konfiguration. Assembler muß es sein da Teile des Codes an bestimmten Stellen stehen müssen. Vielleicht könnte man sich etwas mit inline Assembler zurechtfummeln. Aber das ist ja noch schlimmer. Eine CRT (C-RunTime) gehört zu jedem C-Programm. Nur meistens merkt man eben nichts davon. Beim ARM7 ist das noch harmlos, bei PC Programmen geht es da richtig ab (argv, timezone, atexit(), ...) ;) Das Linkerskript hat von C++ auch noch nichts gehört und muß für die Speicherkonfiguration des verwendeten Controllers angepaßt werden. Dazu muß man aber nicht wissen wie ein Linkerskript funktioniert. Aber das die Flash-Versionen der Programme bei dir nicht laufen ist schon seltsam. Da du FlashMagic verwendest wird die erforderlich Prüfsumme wohl stimmen. OpenOCD muß man zur Prüfsummenberechnung glaube extra auffordern. Probiere das Crossworks doch mal aus. Ich persönlich komme damit nicht zurecht aber das heißt ja nichts.
Hm um die Fehlersuche fortzusetzen würd ich gern mal folgendes ausprobieren: Du sagst ja dass die Projekte bei dir erfolgreich aus dem Flash geladen alle 0.5 Sekunden toggeln...dann nimm bitte doch mal das Projekt, kompiliere es, aber bleib bei P0.30, da dort meine LED ist, und lad die fertige Hex-Datei hoch, die ich dann einfach nur mit Flashmagic in den Flash packe. Und wenns dann nicht geht weiß ich ehrlich gesagt nicht weiter...
Hi So. Hab deinen Sourcecode etwas überarbeitet. Jetzt läuft dein Interrupt auf dem LPC2294. Habe es kompiliert mit WinARM. Eine Beschreibung wie Interrupts Programmiert werden ist unter http://arm.hsz-t.ch zu finden. Gruss, Daniel
@Daniel Schwab Leider geht es immer noch nicht. Ich habe einfach die hex-File aus dem Ordner genommen und mit Flash Magic in den Flas geschrieben...Programm startet, LED leuchet auf, aber sie bleibt dann an und toggelt nicht...langsam bin ich echt am Verzweifeln :-(
@let die hex Datei tut leider überhaupt gar nichts...die LED geht nichtmal an...aber sehr gut dass du das mit dem Timerwert gesehen hast, ich seh vor lauter Bäumen den Wald nicht mehr!! @Daniel Schwab Wenn man den Timerwert verändert, dann toggelt die LED tatsächlich!! :-) Allerdings nicht mit der erwarteten Frequenz, aber das guck ich mir morgen mal in Ruhe an! Hast du vielleicht noch die zu der Startup Datei passende Linkerdatei für den RAM-Modus? Meine geht nicht mit der crt0.s und ich habe hier einen JTAG-Adapter zum Debuggen nur im RAM...wäre super! Und danke mal wieder für Alles! Bin immer wieder begeistert wie geduldig die Leute mit sonem ahnungslosen Kerl wie mir sind! :-)
Ich finde es schon seltsam das auf meinem inzwischen wieder einsatzfähigen und P0.30 tauglichen 2148 Evalboard beide Hexfiles laufen. Mir ist aber inzwischen aufgefallen das die Stackgröße bei meinem Sammelsurium falsch ist. Startcode und Linkerskript sind bei Daniels Variante auch etwas vollständiger (C++). Was bei seinem Beispiel aber fehlt (auskommentiert) ist die Initialisierung der PLL. Der Kern läuft so nur mit dem Quarztakt und der Timer bekommt nur ein Viertel davon. Deine Berechnungen basieren wahrscheinlich auf einem 59MHz Takt. Und da könnte auch der Hund begraben sein: Was hast du denn für einen Quarz? 14.576MHz oder vielleicht 19.xx? Im letzteren Fall wird der Controller bei der Einstellung in den Beispielen übertaktet, bzw. die PLL rastet gar nicht erst ein und der Controller hängt in der PLL Initialisierung fest.
Hi PLL und MAM ist jetzt auch integriert. Quarz läuft mit 12MHz und intern mit 60MHz. Wenn du einen 14MHz Quarz hast, musst du in der Datei system.h dies ändern (PLL_MUL und FOSC). Stimmen die Angaben im system.h wird die Frequenz mit dieser Formel im Programmcode berechnet. T0MR0 = PCLK / (0.5 * 2); Die Stackgrösse habe ich grösser gemacht, da ich oft an die grenzen gestossen bin (von 0x400 auf 0x800). Damit es für das RAM kompiliert wird, kannst du statt ROM -> RAM schreiben. .text : { *crt0.o (.text) /* Startup code */ *(.text) /* remaining code */ *(.rodata) /* read-only data (constants) */ *(.rodata*) *(.glue_7) *(.glue_7t) *(.flash) } > ROM Der Eintrag *(.flash) kannst du löschen. Da hatte ich ein paar Dinge ausprobiert. Gruss, Daniel
aaalso nachdem ich heute morgen meine pllInit in das Programm eingebaut hatte lief es auch wieder mit der richtigen Frequenz und die Timer-Matchwerte entsprechen den berechneten Zeitwerten. Wenn ich die enableIRQ()-Methode auskommentiere, toggelt die LED nicht...die ganzen Methoden in der armVIC.h/.c übersteigen allerdings meine Kompetenz zur Zeit also lass ich das einfach drin in dem Wissen, dass es nötig ist um die Interrupts zu benutzen^^ die enableFIQ werd ich vermutlich benötigen um eine FIQ Routine ans laufen zu kriegen richtig? Wozu sidn die disable bzw. restore Methoden da? Wenn ich nur dieses eine ROM durch RAM ersetze, wie gewohnt openOCD starte und debuggen möchte erscheint jedoch folgende Fehlermeldung: value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check couldn't poll target(-104). It's due for a reset. value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check Program received signal SIGTRAP, Trace/breakpoint trap. 0xffffffee in ?? () Muss ich vielleicht doch mehr tun als dieses eine "ROM" durch "RAM" zu ersetzen? Achso und folgende Warning tritt beim Kompilieren jedes mal auf, kann da jemand was mit anfangen? Warnings(1 item) Error launching external scanner info generator (gcc -E -P -v -dD C:/Projekte/workspace/.metadata/.plugins/org.eclipse.cdt.make.core/specs .c -mcpu=arm7tdmi -Os)
>Wozu sidn die disable bzw. restore Methoden da? Beim AVR nennt sich das cli() und sei(). >Error launching external scanner info generator (gcc -E -P -v -dD Eclipse kann die gcc.exe nicht finden um seine Symbolliste für die Quelldateien zu erzeugen. Du kannst entweder versuchen in den Abgründen der Eclipse Einstellungen (irgendwas mit 'Indexer command' oder so) den arm-elf-gcc einzutragen oder aber du kopierst dir die arm-elf-gcc.exe nach gcc.exe (im selben Verzeichnis von Yagarto). Zum Rest kann ich dir nichts sagen da ich weder den RAM_MODE noch OpenOCD verwende. Aber das sieht doch alles schon ganz gut aus. Die Inkompatibilität zwischen unseren Boards ist noch offen. Vielleicht läßt sich das Geheimnis noch lüften. Ist es der Quarz? So oder so: Willkommen in der ARM-Welt ;)
Hi Ich habe dir ein kleines Beispiel gemacht mit deiner LED Software für Programmcode im SRAM und im FLASH. Der Programmcode der ins SRAM soll, bekommt das Attribut MEMORY. Die definierung dazu liegt in der Datei system.h. Im Linkerfile hat es ebenfalls einen Eintrag gegeben für das MEMORY (.memory). Jetzt sind wir also in der Lage ein einziges hex File zu erzeugen mit Programmcode für das SRAM und FLASH. Die Programmiertools haben eine Kontrolle intern und reklamieren wenn man über den Bereich hinaus des FLASH Speichers schreiben will. Nimm das LPC2000 Tool von Philips mit der Version V2.2.3. Geh erst zum Menü Buffer und wähle dort "RAM Buffer Operation" aus. Lade dort das hex File und klicke dann auf Upload. Das Programm meckert dann zwar, dass es Code hat der ausserhalb des RAM's ist, das soll uns aber nicht stören. Ist der Code im RAM, schliessen wir das Fenster für RAM Operationen und laden nun das gleiche hex File nochmals. Diesmal geht es dann aber ins FLASH. Wieder meckert das Tool, da es Code ausserhalb des Flashspeichers hat. Soll uns wieder nicht interessieren. Hattest du beide Häkchen gemacht, vor dem Upload, startet dein ARM7 nun. Auch bei einem Reset bleibt der Code im RAM erhalten. Schalte nun für kurze Zeit die Spannung aus, dann kannst du sehen, dass der ARM7 nicht mehr toggelt. Da der Code im RAM nun weg ist. Nun beginnen die Spielereien ;-) Wenn du nun das Interface für deine Programmmodule einheitlich machst, kannst du den Programmcode inkl. Speicherbereich austauschen. Das kannst du dir vorstellen, so wie das eine Memory Management Unit macht. Hast du noch eine MMC angeschlossen, kannst du nun ohne weiteres beliebigen Programmcode auslagern und wieder holen inkl. dem dazugehörigen RAM des Programmes. Du hattest ja gefragt, ob es nur mit dem ändern von ROM auf RAM genügt: Ja. Ich hoffe mit dem Beispiel wird es ein wenig besser es zu verstehen.
Also der Quarz auf meinem Board erzeugt einen Takt von 14.7456Mhz...wozu so ein krummer Wert? Ich habe das Gefühl dass die LED länger an als aus ist...dabei sollte sie exakt jede halbe Sekunde toggeln...kann es bedingt durch diese Interrupts zu irgendwelchen Verschleppungen kommen? Des Weiteren wundert es mich, dass mein Display sich völlig anders verhält wenn es über die Interrupt-Methode gesteuert wird als vorher, wo ich den Timer mit if abgefragt hab...vorher stand auf dem Display "LED an" wenn sie an war und "LED aus" wenn sie aus war...nun ist es zwischendurch immer komplett leer... Ist es so, dass nach Abarbeitung der ISR die Ausgänge wieder den Wert annehmen den sie vor Ausführen der ISR hatten? Das könnte es evtl erklären... Und wohin springt das Programm nach abarbeiten der ISR? Wenn es vorher in der while(1)-Schleife in der nichts weiter steht stand, dann springt es da doch auch wieder hin oder? Die Warning ist mittlerweile auch weg, hatte was mit den Properties zu tun...
Steffen Krebs wrote: > Also der Quarz auf meinem Board erzeugt einen Takt von 14.7456Mhz...wozu > so ein krummer Wert? Weil sonst der Bootloader viel langsamer arbeitet: Baudratenquarz.
Okay ich hab das seltsame Problem jetzt gelöst. Es lag woh daran, dass in der ISR variablen definiert und deklariert wurden...wird die definition global gemacht gibt es keine probleme...hat jemand eine Erklärung dafür? der compiler hat darüber nicht gemeckert, nur das Programm hat total merkwürdig darauf reagiert...LED toggelte nich mehr gleichmäßig und auf dem LED passierten auch komische Dinge...jetz hab ich nur noch mit einer "shadowed declaration" zu kämpfen, aber das krieg ich schon hin...is auch nur ne warning^^ Danke für Alles!
Man zeige den aktuellen Quellcode inkl. Startup, das Linkerscript und das Makefile bzw. die verwendeten Assembler/Compiler/Linker-Optionen. Mglw. nur Stack/Stacks nicht richtig oder zu klein initialisiert.
So, dies ist der aktuelle Stand. Funktioniert jetz soweit einwandfrei... Diese shadowed declaration kam dadurch zustande, dass eine der globalen Variablen den selben Namen und Dateityp hatte wie ein Übergabeparameter in einer Funktionsdeklaration. Der andere Fehler, der dafür sorgt dass die LED ungleichmäßig toggelt und auf dem Display merkwürdige Dinge passieren, tritt auf, wenn man die beiden globalen Variablen, die nur in der ISR benutzt werden auch dort erst definiert...warum, ist mir allerdings noch nicht klar. Als Nächstes versuche ich mich am Linker-File...damit ich das Programm in den RAM schreiben kann und den JTAG-Adapter mit OpenOCD zum debuggen nutzen kann anstatt das Programm in den Flash zu schreiben.
Wenn ich oben besagtes ROM durch RAM ersetze, kompiliere und den Debug Modus via OpenOCD starte, stürzt der Debug-Vorgang direkt mit folgender Fehlermeldung ab: value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check couldn't poll target(-104). It's due for a reset. value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check value captured during scan didn't pass the requested check: captured: 0x0f check_value: 0x01 check_mask: 0x0f in_handler reported a failed check
Bei der Version mit lokalen Variablen werden 20 Bytes zusätzlich vom Stack verwendet. Der IRQ-Stack ist derzeit 128 Bytes groß. Mach den doch mal etwas größer. In crt0.S Zeile 14 ist es zu tun. Was du dort hinzufügst wird dir vom "normalen" Stack im System-Mode abgezogen. Insgesamt stehen dir 2048 Bytes zur Verfügung. Eingestellt wird das im Linkerskript Zeile 8.
Hi, ich habe das BlinkLEDirq.rar auch mal ausprobiert. Allerdings habe ich es nur mit dem arm-elf-insight als simulator getestet. In der Funktion pllInit in der Zeile 170 ("while(!(PLLSTAT & PLOCK)) ;") bleibt bei mir der Simulator hängen und macht nicht weiter. Scheint mir so als wenn die Interrupts nicht ausgelöst werden?! Könnte das jemand vielleicht mal ausprobieren , ob der gleiche effekt auftritt?! vielen dank.
Hi Nicht alle Simulatoren Emulieren einen PLL und bleiben hängen, weil PLLSTAT nie das Bit gesetzt wird. Gruss
Vielen dank für deine schnelle antwort. schade.... Kann das vielleicht jemanden bestätigen mit dem arm-elf-insight, das es nicht gehr bzw dort hängen bleibt? danke
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.