Hallo zusammen,
ich versuche gerade den PWM Generator als dritten Timer im LPC2148 zu
nutzen. Leider wird die ISR nie aufgerufen.
Diesen ganzen VIC habe ich aber auch noch nicht vollumfänglich
verstanden. Vielleicht mache ich da etwas falsch. Eine zweite
Interruptquelle (UART0) funktioniert aber. Daher gehe ich davon aus,
dass der Interruptwrapper im Startupcode in Ordnung ist.
So initialisiere ich den PWM Block (VIC_PWM0 ist als 8 definiert):
1
// initialize PWM as timer for BLANK interrupt every 4096 GSCLK pulses
2
PWMPR=1;// set prescaler, with 60MHz PCLK this gives 15 MHz
3
PWMMR0=4096;// set compare match 1, so pin should toggle at 7,5 MHz
4
PWMMCR=2;// set timer to reset on matching MR0
5
PWMTCR=0x02;// reset timer
6
PWMTCR=0x01;// start timer
7
8
// initialize the interrupt vector
9
VICIntSelect&=~VIC_BIT(VIC_PWM0);// PWM0 selected as IRQ
VICVectAddr4=(uint32_t)uart0ISR;// address of the ISR
Ich habe also für beide ISRs unterschiedliche VIVectCntl und -Addr
Register genutzt. Wenn ich es richtig verstehe wird über die Wahl des
Registers die Priorität gewählt. Wenn mir die Prio egal ist, kann ich
dann einfach ein freies Addr Register suchen (z.B. durch Abfrage auf
null)?
Ich habe den Fehler gefunden. Ein Dummfehler. Man sollte den MR0
Interrupt im PWM Block auch aktivieren.
Also statt
1
PWMMCR=2;// set timer to reset on matching MR0
so
1
PWMMCR=3;// set timer to reset and Interrupt on matching MR0
Aber nun habe ich gleich das nächste Problem. Wenn ich in der ISR nicht
abfrage von welcher Quelle (MR0..5) der Interrupt kam, funktioniert
alles. Mache ich eine Abfrage rein, stürzt der LPC ab, die putchar
Schleife wird nicht ausgeführt.
Also so gehts nicht:
1
voidpwm0ISR(void)
2
{
3
if(PWMIR&PWMIR_PWMMR0_Interrupt)
4
{
5
FIO0PIN^=(BLANK+XLAT);// Toggle BLANK Pin
6
}
7
PWMIR=0xff;// Write back to IR to clear Interrupt Flags
8
VICVectAddr=0x0;// End of interrupt execution
9
}
Lasse ich das IF weg, gehts.
Ein weiteres Problem ist, der PWM Timer läuft bei gleicher
Initialisierung viel langsamer als Timer0.
1
// initialize timer 1 pin MAT1.0 for GSCLK output about 7.5 MHz
2
PINSEL0|=0x02000000;// switch pin P0.12 to Timer 1 Channel 0 match
3
T1CTCR=0;// set timer to timer mode (clock timer by PCLK)
4
T1PR=1;// set prescaler, with 60MHz PCLK this gives 15 MHz
5
T1MR0=1;// set compare match 1, so pin should toggle at 7,5 MHz
6
T1MCR=2;// set timer to reset on matching MR0
7
T1EMR|=0x30;// set pin mode of MAT1.0 to toggle
8
T1TCR=0x02;// reset timer
9
T1TCR=0x01;// start timer
10
11
// initialize PWM as timer for BLANK interrupt every 4096 GSCLK pulses
12
PWMPR=1;// set prescaler, with 60MHz PCLK this gives 15 MHz
13
PWMMR0=200;//4096; // set compare match 1, so pin should toggle at 7,5 MHz
14
PWMMCR=3;// set timer to reset and Interrupt on matching MR0
15
PWMTCR=0x02;// reset timer
16
PWMTCR=0x01;// start timer
Beide Timer sollten so also etwa mit 15MHz laufen, am Pin MAT1.0 sollte
also eine Frequenz von 7,5MHz anstehen. Tut sie auch. Der PWM Timer
sollte mit der selben Frequenz bis 200 zählen, also müssten zwischen den
PWM Pulsen 100 MAT1.0-Takte sein. Es sind aber nur 44! Wieso?
Gruß
Thorsten
Da würde ich spontan naschauen ob PWMIR überhaupt korrekt definiert ist
und auf die korrekte Addresse zeigt.
Musste man bei ARM7 nicht auch die ISRs dekorieren damit der Compiler
den korrekten Ein- und Ausgangscode erzeugt? Oder macht das ein
Assembler Stub?
Thorsten E. schrieb:> Der PWM Timer> sollte mit der selben Frequenz bis 200 zählen, also müssten zwischen den> PWM Pulsen 100 MAT1.0-Takte sein. Es sind aber nur 44! Wieso?
Beim LPC17xx gab es noch einen weiteren Vorteile für die jeweilige
Periphere (PCKLSELx), und dessen Default ist 4 - was zu Deiner
Beobachtung ungefähr passen würde.
Jim M. schrieb:> Da würde ich spontan naschauen ob PWMIR überhaupt korrekt definiert ist> und auf die korrekte Addresse zeigt.
Sieht richtig aus:
1
#define PWMIR (*(volatile unsigned long *)0xE0014000)
> Musste man bei ARM7 nicht auch die ISRs dekorieren damit der Compiler> den korrekten Ein- und Ausgangscode erzeugt? Oder macht das ein> Assembler Stub?
Da habe ich unterschiedliche Aussagen gehört. Ich nutze ja die
Vektorinterrupts. Diese rufen ja zunächst alle den IRQ Interruptvektor
auf. Der ist in meinem Startupcode so aufgebaut:
Er sichert erstmal diverse Register, lädt dann den Interruptvektor aus
dem VIC und springt ins entsprechende Programm. Muss er eigentlich
tatsächlich alle Register sichern oder nutzt C gar nicht alle. Oder kann
man womöglich durch die "Dekoration" die genutzen Register begrenzen.
Ich sehe nicht, was das mit der if-Abfrage zu tun haben könnte.
> Beim LPC17xx gab es noch einen weiteren Vorteile für die jeweilige> Periphere (PCKLSELx), und dessen Default ist 4 - was zu Deiner> Beobachtung ungefähr passen würde.
Ja, das stimmt. Der gilt dann ja aber für alle Timer gleichermassen.
Zwei gleich eingestellt Timer sollten ja somit im selben Takt laufen.
Wo ist also der Denkfehler?
Es wird immer seltsamer. Inzwischen ist in der ISR das drin was sie tun
soll:
1
voidpwm0ISR(void)
2
{
3
uint16_ttemp=PWMIR;
4
if(temp&PWMIR_PWMMR0_Interrupt)
5
// if (PWMIR & PWMIR_PWMMR0_Interrupt)
6
{
7
T1TCR=0;// stop timer 1 (GSCLK)
8
FIO0SET=BLANK;
9
FIO0SET=XLAT;
10
// temp=temp & 1; // eat a bit of time
11
FIO0CLR=XLAT;
12
FIO0CLR=BLANK;
13
T1TCR=0x02;// reset timer 1 (GSCLK)
14
T1TCR=0x01;// start timer 1 (GSCLK)
15
}
16
PWMIR=0xff;// acknowledge interrupt
17
VICVectAddr=0x00000000;// clear this interrupt from the VIC
18
}
Funktioniert auch soweit. Aber wenn ich eine der beiden auskommentierten
Zeilen einbaue, stürzt er ab. Versteh ich nicht.
Komischerweise sieht man auch nur den BLANK Puls. Der XLAT Puls ist
nicht zu sehen. Der Timer 1 wird wie geplant kurz unterbrochen.
Thorsten E. schrieb:> Es wird immer seltsamer. Inzwischen ist in der ISR das drin was sie tun> soll:
Irgendwie machst du dir das Leben schwer. Guck mal in die Lernbetty, die
ist ja auch noch ARM7TDMI. Bei mir geht der Interrupt so:
1
VectorsLDRPC,Reset_Addr;I=F=1
2
LDRPC,Undef_Addr;I=F=unchanged
3
LDRPC,SWI_Addr;I=1,F=unchanged
4
LDRPC,Prefetch_Addr;I=1,F=unchanged
5
LDRPC,DataAbort_Addr;I=1,F=unchanged
6
NOP;reserved
7
LDRPC,[PC,#-0x0FF0];IRQ,HandlerAddr-->PC
8
LDRPC,FIQ_Addr;FIQ
Ja - das ist alles. Der Einzeiler "LDR PC,[PC, #-0x0FF0]" erledigt
das, was in Assembler getan werden muß. Den Rest erledigt der Compiler
bei deinem Interrupt-Handler.
Aber dafür mußt du:
1. deine ISR im ARM-Mode, also nicht thumb übersetzen
2. deine ISR mit dem gehörigen Attribut __isr kennzeichnen. (oder eben
mit dem Gcc-Äquivalent dazu)
Und nochwas: Guck auf deine Stacks und deren Größe. Du weißt, daß du
hier für jede Interrupt-Klasse einen separaten Stack hast, ja?
W.S.
Diesen Einzeiler hab ich auch schonmal gesehen aber in keinster Weise
verstanden was und vor allem WIE der tun soll.
Ich vermute #-0xff0 heißt soviel wie aktuelle PC Position - 0x0ff0. Da
der PC ja irgendwo nahe Null steht, lande ich also am Ende des
Adressierbaren Speichers, da ist aber nichts.
Von Lernbetty hatte ich bisher nichts gehört, obwohl hier sogar eine
rumliegt. Dein Artikel dazu ist ja sehr interessant aber auch
abschreckend.
Ist dieses ganze Verwirrspiel mir ARM und Thumb Mode und den diversen
Stacks bei den neueren ARMs (STM32) auch so? Wenn ja, werde ich mit der
ARM Familie wohl nie anfreunden. Wenn es da nicht so ist, wird der alte
LPC jetzt weggeschmissen und auf STM32 umgestellt. Muss ich halt ein
kleines STM Platinchen an die vorhandene Displayplatine ranstecken und
den LPC nicht bestücken. Gott sei Dank hab ich die Displaysignale auf
einen Pfostenstecker gelegt.
Jetzt weiß ich auch warum in den Beispielsourcen vom Board immer die
ISRs in extra Dateien steckten, weil diese alberne ARM / Thumb
Umschaltung ja beim gcc demnach nicht innerhalb einer Datei
funktioniert.
Und wie sage ich meinem Makefile, dass die eine Datei im thumb Mode und
die andere im ARM Mode übersetzt werden muss (Ja, ich weiß Makefiles
sind böse). Wenn ich eh jede Datei einzelnd auflisten muss sind sie in
der Tat sinnlos.
Im Moment ist mein Programm komplett im Thumb Mode übersetzt, was wohl
auch das seltsame Verhalten erklärt.
IRQ Size ist übrigens 512 Bytes was wohl selbst für das bisschen
if-Bedingung reichen sollte.
Und die unterschiedlichen Timerfrequenzen trotz gleicher Konfiguration
kann ich auch nicht erklären.
Kann man an irgendeinem Listing des gcc erkennen welche Funktionen in
welchem Modus übersetzt wurden. Ich versuche immer noch zu verstehen wie
die mitgelieferten Beispielsourcen funktionieren.
Im Makefile werden alle Sourcen, egal ob Interrupt oder normal gleich
behandelt. Es gibt weder arm noch thumb Schalter.
Der gcc wird für C Dateien so aufgerufen:
Genauso mache ich es auch. Das Testprogramm funktioniert, mein eigenes
zickt mit der ISR.
Achja, er zickt NUR mit der Timer ISR rum. Die UART ISR funktioniert
einwandfrei und ist deutlich umfangreicher als die Timer ISR. Und das
liegt nur an ARM/Thumb oder IRQ-Handler? Eigenartig.
Thorsten E. schrieb:> Wenn es da nicht so ist, wird der alte> LPC jetzt weggeschmissen und auf STM32 umgestellt
Du kannst den alten LPC2148 ARM7 durch pingleiche LPC17xx M3 oder
LPC40xx M4 ersetzen, da ist die IRQ Problematik gelöst und sind zudem
einfacher "direkt" programmierbar als die STM32
Lothar schrieb:> Du kannst den alten LPC2148 ARM7 durch pingleiche LPC17xx M3 oder> LPC40xx M4 ersetzen, da ist die IRQ Problematik gelöst und sind zudem> einfacher "direkt" programmierbar als die STM32
Bist Du sicher, dass es pingleiche Prozessoren gibt? Ich habe gerade mal
die beiden genannten Reihen überflogen. Der LPC2148 hat ein LQFP64
Gehäuse. In beiden Familien habe ich keinen Prozessor mit identischem
Gehäuse gefunden.
Bei Mouser finde ich immerhin zwei:
MKV31F512VLH12
LPC54113J128BD64QL
Ich habe nun den Rat von W.S. befolgt und meine ISR Routine als ISR
gekennzeichnet und den Startupcode bereinigt. Dort habe ich die (mir
unverständliche) Zeile
ldr PC, [PC,#-0xFF0]
anstelle des Links auf den ISR Handler ersetzt.
Am Verhalten hat sich dadurch nichts verändert. Mit der markierten Zeile
stürzt es ab, ohne läuft es.
Ach ja, ich habe alle im ARM Mode compiliert (-marm)
1
__reset:
2
ldr pc, reset_handler_address
3
ldr pc, undef_handler_address
4
ldr pc, swi_handler_address
5
ldr pc, pabort_handler_address
6
ldr pc, dabort_handler_address
7
.word 0xB8A06F58 /* 0 - (sum of other vectors instructions) */
Ich habe nun mal die ISR auf das nötigste minimiert und das
Assemblerlisting erzeugt. Ich versteh allerdings den Assemblercode fast
gar nicht. Vielleicht kann ja jemand was damit anfangen und mir einen
Tipp geben was falsch läuft.
Übrigens: wenn ich den Befehl zu Zeit verbrennen mit einer anderen
Variable mache als temp funktioniert es auch. Irgendwie scheint beim
Zugriff auf temp irgendwas schief zu laufen.
Hier die ISR in C:
1
// Die folgenden defines stehen so in der lpc_2148.h
2
// #define PWMIR (*(volatile unsigned long *)0xE0014000)
Bis zum Schreiben der diversen Register kommt er. Beim Lesen in die
Variable dummy crasht er dann. Anscheinend darf ich nicht lesend auf
Register zugreifen. Komischerweise klappt das aber bei den UART
Registern.
Ich weiß nicht, ob man hier ZIP Files anhängen darf. Dann könnte ich mal
ein Minimalprojekt zusammenstellen.
Gruß
Thorsten
Das sieht ja alles grauenvoll aus!
Thorsten, wie groß ist denn deine Firmware? Vielleicht solltest du es
doch zuerst mal mit dem Keil versuchen. Oder alternativ mit dem
Batchfile, was in der Lernbetty die Übersetzung erledigt. Eben ohne Make
und auch ohne Linkerskript. Bei der Betty ist das problemlos gegangen.
Das Einzige, was mir damals ein Ärgernis war, ist der Umstand, daß man
beim Gcc in Assembler mit thumb code nicht nur .thumb schreiben darf,
sondern vor jede exportierte Funktion noch .thumbfunc oder so ähnlich,
weil dieser Mist-Gcc sonst thumb code erzeugt, ihn aber im Objektfile
als arm code markiert. Folglich baut der Linker einen Interfacecode
thumb<-->arm dazwischen ein, was zum gnadenlosen Absturz führt. Hat mich
damals einige graue Haare gekostet.
Also nochmal: hast du deinen Interrupt im VIC auch nicht als fast
gekennzeichet? Der FIC benutzt einen anderen Stack als der gewöhnliche
Interrupt, dafür hat er auch einen separaten Satz an Registern (ab R7,
wenn ich mich recht erinnere). Guck dir den Startupcode von der
BettyBase in der Lernbetty an, dort wirst du das alles sehen. Zuoberst
hat es die Stacks für undef, abort, FIQ, normale IRQ's (mach den nicht
zu klein, wenn du lokale Variablen benutzt!), dann den Supewrvisor-Stack
(als den für OS-Aufrufe per SVC), dann den ordinären User-Stack. Wenn du
die oberen Stacks zu klein machst und lokale Variablen anlegst oder zu
viele Register auf den Stack pushst, dann zerdrischst du dir deinen
Userstack damit.
Und zum "ldr PC, [PC,#-0xFF0]":
Der lädt den Inhalt des VIC-Registers für die Handler-Adresse des gerade
aktuellen Interrupts in den PC. Das LR bleibt dabei unberührt und damit
landet der Prozessor direktemang am Eingang der ISR, die tatsächliche
Rückkehradresse im LR ist so, als käme er ohne den Startupcode direkt
von dort her und der Rest ist Sache des Interrupt-Handlers. Der kehrt
übrigens nicht auf die gleiche Weise zurück wie eine ordinäre Funktion.
Beim FIQ ist das z.B.
" SUBS PC,LR,#4 "
In der Lernbetty hatte ich den FIC zusammen mit einem Timer für die
Audio-Ausgabe ("willkommen an board.." mit 11.025 kHz Samplerate)
benutzt. Pro Sample gibt's einen Interrupt vom Timer, die ISR lädt den
nächsten Wert in das Compare-Register, der Wert wird also per Pulsbreite
ins Analoge übersetzt und fertig. Da sollte es dir doch wohl auch
gelingen, deinen Timer-Interrupt erfolgreich hinzukriegen.
W.S.
Wie gesagt, selbst ganz ohne Interrupts crasht das Ding beim Lesezugriff
auf einige Register. Wahrscheinlich macht der gcc irgendeinen Müll.
Im Moment ist mein Code winzig, ich habe aber keine Lust erst Keil zu
lernen und dann später das gcc Drama zu wiederholen.
Und mit dem STM32F103 scheint es ja zu gehen. Also vielleicht lieber
dieses Antik Dingens in den Müll werfen. Verstehe eh nicht was die
Entwickler von dem Ding geraucht habe, mit seinen diversen Stacks und
Modi. Sowas kann ich ja vielleicht verstehen für Multiuser Serversysteme
aber doch nicht für nen Controller der eine Waschmaschine steuert.
Thorsten E. schrieb:> Und mit dem STM32F103 scheint es ja zu gehen. Also vielleicht lieber> dieses Antik Dingens in den Müll werfen. Verstehe eh nicht was die> Entwickler von dem Ding geraucht habe, mit seinen diversen Stacks und> Modi. Sowas kann ich ja vielleicht verstehen für Multiuser Serversysteme> aber doch nicht für nen Controller der eine Waschmaschine steuert.
Hehe!
Also erstens ist der STM ne ganz andere Konstruktion - und er ist viel
neuer und er hat jedenfalls bei den M-Typen keine
Betriebsystem-Vorkehrungen intus außer dem SVC.
Zweitens ist der ARM7TDMI durchaus kein antiker Müll. Er will aber
verstanden sein. Ich hab mit genau diesen Chips ne Menge Geräte draußen
bei den Kunden und bei näherer Betrachtung hat diese Architektur
durchaus ihren Reiz. z.B. mit dem FIQ kann man wesentlich besser
hantieren als mit einem simplen DMA.
Drittens ist die Architektur tatsächlich für größere Systeme ausgelegt,
wo man eben ein Betriebssystem hat, was allerdings in der Praxis einen
ARM9 oder StrongArm haben will - wegen der virtuellen Adressen. Zum
Beispiel Epoc bzw. Symbian, zum Beispiel Windows CE. Eben deswegen hat
man da eben einen Sack unterschiedlicher Stacks, von denen man auf nem
LPC2103 oder so nur wenige tatsächlich braucht. Sieh das mal so wie
Linux: Das zugrundeliegende Unix wurde auch für mittlere Datentechnik
gemacht und wenn du es auf einem Einplatinenrechnerlein laufen läßt, hat
es konstruktionsbedingt eben auch Eigenheiten, die eigentlich nur auf
nem Mainframe so richtig greifen würden.
OK, hier hat jemand IAR vorgeschlagen, diese Compiler kenne ich nur für
NEC, dort braucht man aber durchaus ne dedizierte Linker-Konfiguration -
mag sein, daß das auch für die ARM-Version gilt.
Vorschlag: Du postest mal dein Projekt und alle anderen fallen drüber
her und mosern. Ich hab noch Platinen mit ähnlichen LPC's, könnte also
notfalls mal ne Übersetzungsprobe+Test machen und dann mitmosern.
W.S.
Ich werde nachher mal versuchen mein Prijekt auf das minimalste
zusammenzustreichen. Wenn dann der Fehler reproduzierbar ist, poste ich
es. Darf man eigentlich zip Dateien posten?
Leider krieg ich den Fehler nicht mit einem minimertem System
zuverlässig reproduziert. Füge ich eine Zeile hinzu, gehts plötzlich.
Noch eine, dann wieder nicht. Ich verstehe nicht was passiert.
Dann fiel mir auf, immer wenn es NICHT funktioniert macht der OpenOCD
folgende Meldung beim Flashen:
Info : Padding image section 1 with 8 bytes
Wenn es funktioniert kommt die Meldung nicht. Also habe ich eine
schlechte Version mal mit Flashmagic geflasht. Geht leider auch nicht.
Ich finde leider nicht was die Meldung bedeutet. Ich vermute irgendetwas
ist nicht korrekt aligned.
Es scheint auch so zu sein, dass wenn es nicht funktioniert, er nichtmal
nach main kommt.
Dann habe ich versucht mit GDB zu debuggen um zu sehen wo er hängt. Hier
mal der Versuch:
Interessanterweiser sieht gdb nach einem "monitor reset halt" zunächst
gar keine Software (0xff) ab Adresse 0. Nach dem ersten Step sieht er
plötzlich etwas, aber nicht das was da sein sollte!
Der Anfang meines startupcode sieht so aus:
1
.section .reset, "ax"
2
.global __reset
3
.global __main
4
.code 32
5
6
__main:
7
__reset:
8
ldr pc, reset_handler_address
9
ldr pc, undef_handler_address
10
ldr pc, swi_handler_address
11
ldr pc, pabort_handler_address
12
ldr pc, dabort_handler_address
13
.word 0xB8A06F58 /* 0 - (sum of other vectors instructions) */
14
ldr pc, irq_handler_address
15
ldr pc, fiq_handler_address
Möglicherweise sehe ich das Starten des internen Bootloaders des
Prozessors. Das nützt mir aber nichts. Nach dem siebten Step (ab Adresse
0x0000001c steht ich dann im Wald:
Für den Fall das jemand Lust hat sich das Ganze mal anzusehen habe ich
mal das Projekt angehängt.
Im den Quellen und dem Makefile habe ich einige Kommentare zu den
Fehlern angegeben.
Grundsätzlich fällt auf, dass es überhaupt nur funktioniert wenn das
ganze Projekt im ARM Modus übersetzt wird. Im Thumb Modus geht es gar
nicht. Wäre für mich aber auch ok. Im Moment wird es auch, glaube ich,
komplett im SVC Modus ausgeführt, wäre für mich zwar auch ok, ist aber
vielleicht Teil des Problems. Vielleicht nutze ich dadurch den falschen
Stack?
Das im vorigen Post angegebene Problem mit dem "Padding image" scheint
doch nichts mit dem Fehler zu tun zu haben. Ich hatte inzwischen auch
Fälle wo es trotz der Meldung funktioniert hat.
Die magische Zeile im startup Code "ldr pc, [PC,#-0xFF0]" geht
plötzlich nicht mehr, ich weiß aber nicht warum. Es hatte zunächst
funktioniert.
Insgesamt also alles recht wirr und nicht wirklich reproduzierbar.
Achja: hat jemand einen Tipp wie man gcc oder OOCD dazu bringt, die
Prüfsumme für den Bootloader in der Vectortabelle automatisch
einzusetzen. OOCD zeigt die nötige Prüfsumme immerhin an, so dass ich
sie von da aus abtippen kann.
Kann es sein, dass der aktuelle arm-gcc die ARM7tdmi Cores nicht mehr
richtig unterstützt? Aif der Webseite sieht man nur noch was von Cortex
Cores. Und wenn gcc es noch kann, kann es vielleicht an der Multilib
liegen.
Muß ich vielleicht einfach etwas älteres nehmen?
Thorsten E. schrieb:> Achja: hat jemand einen Tipp wie man gcc oder OOCD dazu bringt, die> Prüfsumme für den Bootloader in der Vectortabelle automatisch> einzusetzen. OOCD zeigt die nötige Prüfsumme immerhin an, so dass ich> sie von da aus abtippen kann.
Laß das lieber, setze dort einfach einen NOP ein und benutze FlashMagic.
Ich schau mir morgen mal dein Miniprojekt näher an.
W.S.
Ich habe nun ein noch kleineres Projekt gemacht. Dieses stammt
eigentlich von Olimex und war ursprünglich nur ein Blinkprogramm welches
mit dem arm-elf-gcc zu übersetzen ist. Ich übersetze es aber mit
arm-none-eabi-gcc 5.4.1 20160919.
Hier habe ich nun meine Uartroutine eingebaut, die man per Schalter im
Headerfile auf mit oder ohne Interrupt umschalten kann.
Benutze ich die gcc Parameter aus dem Originalprojekt funktioniert es,
auch mit Interrupt. Aber ich kann keine Long Arithmetik nutzen.
Aktiviere ich die auskommentierte Zeile 58 in main.c meckert der
Compiler:
Im Makefile kann man das umschalten durch umkommentieren der Zeilen
21/22 und 38/39.
Dann läuft das Programm aber nur noch ohne Interrupts. Mit Interrupts
stürzt es ab.
Es scheint also irgendwie mit der Art des Linkens zu tun zu haben.
Vielleicht wird wirklich eine falsche Multilib genutzt.
Nachtrag: poste mal dein lpc_2148.h und lpc_scb.h
Ansonsten sieht dein Zeug grauslig aus: wozu all der syscalls.c Kram?
Auf einem µC geht es ja doch etwas anders zu als auf dem PC - das mit
Gewalt gleich schleifen zu wollen, halte ich für keine gute Idee.
Mir ist da in syscalls.c nochwas auf die Schnelle aufgefallen:
char *__env[1] = { 0 };
char **environ = __env;
Ich nehme an, daß das ne Abwürge ist, die du dann besser als const...
auszeichnen solltest.
Nochwas zum Startup:
.section .reset, "ax"
.global __reset
.code 32
(hier die Vektoren, dann:)
.text
.code 32
.align 0
finde ich nicht so prickelnd. Eher sowas:
.section .text.startup
.func Vectors
.arm
(hier dann die Vektoren)
Guck dir zu den Sektionen und ihrer Linkreihenfolge mal das
Standard-Linkfile an, was der Linker von deiner Distribution intus
hat.
und weiter:
// call main
.extern main
ldr r0,=main
mov pc, r0 /* goto main() */
finde ich auch nicht gut. Was bitte sehr ist, wenn main mal NICHT im
ARM mode übersetzt ist?
Also:
.extern main
LDR R0, =main
BX R0
oder wenn du das Rückkehren nicht ausschließen kannst wegen
irgendwelcher eingebundener Units, die ich nicht kennen kann:
BLX R0
Mein wirklich allerdringendster Rat: Lade dir die Lernbetty runter, lies
den Startupcode durch (es gibt zwei: einer für Keil formuliert, der
andere für Yagarto 4.irgendwas).
Anschließend nimmst du den für Yagarto dir mal vor, schmeißt alles, was
mit dem externen Busanschluß zu tun hat, raus. Ebenso das, was mit dem
Display zu tun hat (PixLane1 und 2, DirtyPages usw.). Dann kürzt du den
SWI-Handler zusammen, bis auf den SWI_dead.
Dann mußt du noch dein Mem-Accelerator-zeug (MAM...) von deinem Startup
reinkopieren (die Betty hat nur externen Flash) und ggf. das Kopieren
der Vorbelegungs-Daten in den RAM auch reinkopieren. Guck auch nach der
PLL-Einstellung, die ist bei der Betty gleich im Startup drin, die läuft
mit 30 MHz obwohl sie deutlich höher könnte (75MHz) - ist alles mE
ausreichend kommentiert.
Anschließend benutzt du diesen Startup anstelle deines bisherigen
Startup's, sparst dir das separate Einstellen der PLL und vermutlich
läuft dann dein Projekt schon.
Nochwas: deine UART-Bedienung sieht aufgebläht aus und stammt vermutlich
aus noch einer anderen Quelle als dein Startupcode. Die diversen Modi
wirst du im konkreten Projekt eher nicht brauchen und manche
Kombinationen funktionieren auch nicht - soweit ich mich da dunkel
erinnere. 8N1 geht aber immer und wird auch am meisten gebraucht... Ich
finde die Rx-Buffer überflüssig und die Tx-Buffer viel zu klein. Ich
hänge dir mal was zum Lesen dran. Ich finde, das "gio.c" Konzept paßt
ganz gut in ein µC-Projekt, da es die HW passabel abstrahiert und kaum
aufträgt. Man sollte da bloß in main ne erste Festlegung treffen a la "
StdIO = toUART0;"
W.S.
Das aus der Lernbetty rauszuholen hab ich schon gemacht. Zum Beispiel
das Main korrekt via Abfrage Thumb oder Nicht-Thumb aufzurufen und auch
die Section Definitionen sowie die Stack Initialisierung. Hilft aber
alles nicht.
Was ich halt eigenartig finde, warum es mal geht und mal nicht. Das
Verhalten ändert sich nur dadurch, dass man irgendwo harmlose Befehle
einfügt, wie das Aufrufen einer leeren Funktion oder auch das Weglassen
der Portzugriffe eines der Beiden Pins in der Timer ISR. Und überhaupt,
der zweite Pin wird gar nicht geschaltet.
Im Zusammenhang mit dem neuen Beispiel, das ja ein ganz anderes fertiges
Winzigprojekt von Olimex als Ursprung hat und das sich unterschiedlich
verhält je nach Linkereinstellung vermute ich, irgendwas stimmt mit dem
gcc nicht. Vielleicht sage ich ihm nicht richtig welchen Prozessor ich
habe und welche C Libraries er nehmen soll. Ich finde es zum Beispiel
sehr eigenartig, dass es anscheinend nur eine "Multilib" für alle ARM
Kerne geben soll. Ist das wirklich so? Oder muss ich vielleicht schlicht
den älteren arm-elf.gcc nutzen, weil der neue die älteren Nicht-Cortex
Cores nicht richtig unterstützt.
Die Startup Files meines gcc sind anscheinend alle für Cortex Cores.
Meine Uartroutinen sehen schlimmer aus als sie sind. Ok, die vielen Modi
Definitionen sind sicherlich etwas zu viel, aber die eigentlichen
Routinen sind m.E. recht schlank (sie waren noch größer, mit Hardware
Handshake und so). Schön finde ich, dass man mit einem define mal eben
das Ganze zwischen Interrupt und kein Interrupt umschalten kann.
Und was syscalls betrifft habe ich andere Ansichten als Du (W.S.). Warum
soll ich nicht die Standard-IO nutzen wenn ich 512kB Flash habe. Da
passten früher mal mindestens zwei komplette Betriebssysteme rein. Und
in meiner Anwendung will ich später auch Zugriff auf ein Filesystem
haben. Dann brauche ich also auch noch File-IO. Ok, kann man alles mit
proprietären Funktionen machen, dann kann man sein Haputprogramm aber
nicht mehr einfach so auf dem PC austesten. Ich hätte es daher halbwegs
portabel. Und wozu soll ich dann eine stdio selbst erfinden wenn sie
schon da ist.
Nur für Console-IO wäre es sicher übertrieben.
Und am syscall liegt mein Fehler auch nicht. Das hatte ich schonmal
komplett rausgenommen.
Thorsten E. schrieb:> Ich finde es zum Beispiel> sehr eigenartig, dass es anscheinend nur eine "Multilib" für alle ARM> Kerne geben soll. Ist das wirklich so?
Für alleARM-Kerne eine einzige Multi-Lib? Das kommt mir sehr spanisch
vor. Soweit ich mich erinnere, gab es bei Yagarto einen Sack voll
unterschiedlicher Libs - was ja auch ganz normal ist, wenn man ARM's
verschiedener Generationen abdecken will.
Thorsten E. schrieb:> Warum> soll ich nicht die Standard-IO nutzen wenn ich 512kB Flash habe.
Wenn alles klappt wie am Schnürchen, dann kann man ja machen was man
will.
Aber wenn es klemmt und man nicht weiß, an welcher elenden Stelle da was
schief läuft, dann mache ich zumindest es so, daß ich alles was nicht
unbedingt sein muß, rauswerfe.
Für Standard-PC-C ist auch dynamische Speicherverwaltung mit dabei,
soweit ich weiß, braucht all sowas wie printf und Konsorten was davon -
und das klebt in irgendwelchen Libs, von denen du nicht weißt, ob da
irgendwas nicht richtig initialisiert ist. Also besser das Ganze
runterbrechen bis auf das, was im eigenen Verzeichnis steht und
möglichst übersichtlich ist - jedenfalls so lange, bis dein Grundgerüst
sauber steht.
Deine CFLAGS und AFLAGS bei der Blinkdemo kommen mir auch seltsam vor
und das Makefile von deinem MiniSample ist mir zu lang, um mich da
durchzuquälen. Frag mal Jörg, denn siehe da:
1
# WinAVR Sample makefile written by Eric B. Weddington, Jörg Wunsch, et al.
2
# Released to the Public Domain
3
# Please read the make user manual!
Es ist wohl eher für die AVR geschrieben und nicht für ARM. Im Prinzip
müßten mMn. die CFLAGS eher so aussehen:
1
-mcpu=arm7tdmi-s
2
-Wall
3
-mthumb-interwork
4
-msoft-float
5
-DGCC
6
-ggdb
7
-IE:/yagarto/include-I.
8
-mthumb
9
-O2
10
-c
und die AFLAGS etwa so:
1
-mcpu=arm7tdmi-s
2
--gstabs
3
-mthumb-interwork
4
-mfpu=softfpa
Aber du fragst da besser einen Make-Fan, denn ich selbst benutze weder
Gcc noch Make. Vergiß nicht, daß die Make-Version bei der Lernbetty von
Siegfried kommt. Mein Zeugs sind die cccgcc.bat, compile_gcc.xcl und
link_gcc.xcl. Der Startup_LPC2220gcc.asm ist gleich für beides, was mit
Gcc gemacht wurde. Alles, was nur für den Keil ist, endet auf arm, also
cccarm.bat und so.
W.S.
Endlich habe ich wieder Zeit gefunden an meine LPC2148 rumzufrickeln.
Und was soll ich sagen, die Wurzel allen Übels ist mal wieder die
Updateritis.
Ich habe nun einen alten arm-elf-gcc (4.6.3) genommen und siehe da, es
geht alles. Das Programm macht ohne Änderung was es soll. Keine Abstürze
mehr. Ich darf long Arithmetik verwenden und auch meine leere Init
Funktion aufrufen.
Einzig eine Sache ist seltsam, ich muss als Compileroption -mhard-float
mitgeben, sonst meckert der Linker dass newlib mit hard-float und mein
Programm mit soft-float übersetzt wurde und daher nicht linkbar ist.
Vermutlich aber egal, solange ich kein FP nutze.
Inzwischen habe ich die komplette Signalerzeugung für eine Kette von
TLC5948 im Gange. Auf dem LA sieht alles sauber aus. Die Tage werde ich
dann mal das Testdisplay dran drahten.
Viele Grüße
Thorsten