Forum: Mikrocontroller und Digitale Elektronik PWM interrupt am LPC2148


von Thorsten E. (bluescreen)


Lesenswert?

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
10
    VICIntEnable |= VIC_BIT(VIC_PWM0);    // PWM0 interrupt enabled
11
    VICVectCntl5 = VIC_ENABLE | VIC_PWM0;
12
    VICVectAddr5 = (uint32_t)pwm0ISR;     // address of the ISR
13
14
    while (1)
15
    {
16
//        pwm0ISR();   // call ISR manually for test, das funktioniert
17
        putchar('*');  // zum Testen ob er noch lebt, tut er.
18
    }

Und hier die ISR:
1
void pwm0ISR(void)
2
{
3
 long int readVal;
4
 readVal = PWMIR; // Read current IR value
5
 FIO0PIN ^= (1<<BLANK); // Toggle BLANK Pin
6
 PWMIR = readVal; // Write back to IR to clear Interrupt Flag
7
 VICVectAddr = 0x0; // End of interrupt execution
8
}

Zum Vergleich hier noch die VIC Initialisierung der funktionierenden 
UART0 ISR:
1
    // initialize the interrupt vector
2
    VICIntSelect &= ~ VIC_BIT(VIC_UART0);  // UART0 selected as IRQ
3
    VICIntEnable |= VIC_BIT(VIC_UART0);    // UART0 interrupt enabled
4
    VICVectCntl4 = VIC_ENABLE | VIC_UART0;
5
    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)?

: Bearbeitet durch User
von Thorsten E. (bluescreen)


Lesenswert?

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
void pwm0ISR(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

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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:
1
/*--- IRQ Handler ----------------------*/
2
.set VIC_base_addr, 0xFFFFF000
3
.set VIC_vect_offs, 0x30
4
5
_irq_handler:
6
        stmfd  sp!,{r0-r12,lr}              // save ALL registers
7
        ldr    r14, =VIC_base_addr          // get VIC's base address
8
        ldr    r0 , [r14, #VIC_vect_offs]   // load interrupt vector
9
        mov    r14, pc                      // save program counter
10
        bx     r0                           // jump to interrupt vector
11
        ldmfd  sp!,{r0-r12,lr}              // restore registers
12
        subs   pc,lr,#4                     // return from IRQ
13
/*--------------------------------------*/

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?

von Thorsten E. (bluescreen)


Lesenswert?

Es wird immer seltsamer. Inzwischen ist in der ISR das drin was sie tun 
soll:
1
void pwm0ISR(void)
2
{
3
    uint16_t temp=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.

von W.S. (Gast)


Lesenswert?

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
Vectors         LDR     PC,Reset_Addr          ; I = F = 1
2
                LDR     PC,Undef_Addr          ; I = F = unchanged
3
                LDR     PC,SWI_Addr            ; I = 1, F = unchanged
4
                LDR     PC,Prefetch_Addr       ; I = 1, F = unchanged
5
                LDR     PC,DataAbort_Addr      ; I = 1, F = unchanged
6
                NOP                            ; reserved
7
                LDR     PC,[PC, #-0x0FF0]      ; IRQ, HandlerAddr-->PC
8
                LDR     PC,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.

von Thorsten E. (bluescreen)


Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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:
1
arm-none-eabi-gcc -I ./ -I ../Source/Platform/Inc -I ../Source/Utils/Inc -mcpu=arm7tdmi -mlittle-endian -Wall -march=armv4t -fno-builtin test.c -o test.o

Der gcc wird für Assemblerdateien so aufgerufen:
1
arm-none-eabi-gcc --traditional-format -march=armv4t -EL startup_gcc.s -o startup_gcc.o

Der Linker so:
1
arm-none-eabi-gcc -nostartfiles -I. startup_gcc.o test.o --output test.out -Wl,-Map=$(OBJ)/$(IMAGE).map,--cref  -lc -lm -lc -lgcc -Tlpc2148_gcc.ld

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.

: Bearbeitet durch User
von Lothar (Gast)


Lesenswert?

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

von Thorsten E. (bluescreen)


Lesenswert?

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

von Lothar (Gast)


Lesenswert?

Thorsten E. schrieb:
> MKV31F512VLH12
> LPC54113J128BD64QL

Die sind bestimmt nicht pingleich. Ich befürchte genau für den 
LPC2148/64 gibt es keinen Ersatz, obwohl es hier behauptet wird:

"Pin-compatible with ARM7 LPC2x00"

http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-mcus/lpc1700-cortex-m3:MC_1403790745385

Wenn ohnehin das Design geändert werden muss, lohnt sich der Umstieg auf 
die neuesten LPC. Hier kommt es auf die Anwendung an.

Die LPC54000 haben mehrere asymmetrische Cores und sind besonders für 
Echtzeit geeignet. Und sind trotzdem einfach zu Programmieren: für jeden 
Core ein separates Programm und Daten werden über gemeinsames RAM 
ausgetauscht. Ein Core macht z.B. ADC ein anderer Filter und ein 
weiterer CAN. Sowas gibt es bei den STM32 nicht, die machen das 
klassisch mit ART und DMA was aber viel komplizierter ist.

http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-mcus/lpc54000-series-cortex-m4-mcus:MC_1414576688124

Die LPC1500 sind Nachfolger der LPC1700 und speziell für 
Motorsteuerungen:

http://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-mcus/lpc1500-cortex-m3:MC_1403790713448

von Thorsten E. (bluescreen)


Lesenswert?

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) */
8
//        ldr  pc, irq_handler_address
9
        ldr  pc, [PC,#-0xFF0] 
10
        ldr  pc, fiq_handler_address
1
static __attribute__ ((interrupt ("IRQ"))) void pwm0ISR(void)
2
{
3
    uint16_t temp=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, diese Zeile muss auskommentiert werden damit es geht
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
}

von Thorsten E. (bluescreen)


Lesenswert?

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)
3
// #define PWMIR_OFFSET 0x0
4
// #define PWMIR_PWMMR0_Interrupt_MASK 0x1
5
// #define PWMIR_PWMMR0_Interrupt 0x1
6
7
static __attribute__ ((interrupt ("IRQ"))) void pwm0ISR(void)
8
{
9
    static unsigned long temp;
10
    temp=PWMIR;
11
    if (temp & PWMIR_PWMMR0_Interrupt)
12
//    if (PWMIR & (uint32_t)PWMIR_PWMMR0_Interrupt)
13
    {
14
//        T1TCR   = 0;     // stop timer 1 (GSCLK)
15
//        FIO0SET = BLANK;
16
        //FIO0SET = XLAT;
17
        temp=temp + 1;     // eat a bit of time, hier crasht es
18
        //FIO0CLR = XLAT;
19
//        FIO0CLR = BLANK;
20
//        T1TCR    = 0x02; // reset timer 1 (GSCLK)
21
//        T1TCR    = 0x01; // start timer 1 (GSCLK)
22
    }
23
    PWMIR   = 0xff;  // acknowledge interrupt
24
    VICVectAddr = 0x00000000;             // clear this interrupt from the VIC
25
}

Und hier das zugehörige abstürzende Assemblerlisting:
1
  .cpu arm7tdmi
2
  .fpu softvfp
3
  .eabi_attribute 20, 1
4
  .eabi_attribute 21, 1
5
  .eabi_attribute 23, 3
6
  .eabi_attribute 24, 1
7
  .eabi_attribute 25, 1
8
  .eabi_attribute 26, 1
9
  .eabi_attribute 30, 6
10
  .eabi_attribute 34, 0
11
  .eabi_attribute 18, 4
12
  .arm
13
  .syntax divided
14
  .file  "tlc5940.c"
15
  .text
16
  .align  2
17
  .size  __sputc_r, .-__sputc_r
18
  .align  2
19
  .ascii  "pwm0ISR\000"
20
  .align  2
21
  .word  4278190088
22
  .type  pwm0ISR, %function
23
pwm0ISR:
24
  @ Interrupt Service Routine.
25
  @ args = 0, pretend = 0, frame = 0
26
  @ frame_needed = 1, uses_anonymous_args = 0
27
  str  ip, [sp, #-4]!
28
  mov  ip, sp
29
  stmfd  sp!, {r2, r3, fp, ip, lr, pc}
30
  sub  fp, ip, #4
31
  ldr  r3, .L7
32
  ldr  r3, [r3]
33
  ldr  r2, .L7+4
34
  str  r3, [r2]
35
  ldr  r3, .L7+4
36
  ldr  r3, [r3]
37
  and  r3, r3, #1
38
  cmp  r3, #0
39
  beq  .L6
40
  ldr  r3, .L7+4
41
  ldr  r3, [r3]
42
  add  r3, r3, #1
43
  ldr  r2, .L7+4
44
  str  r3, [r2]
45
.L6:
46
  ldr  r3, .L7
47
  mov  r2, #255
48
  str  r2, [r3]
49
  ldr  r3, .L7+8
50
  mov  r2, #0
51
  str  r2, [r3]
52
  mov  r0, r0  @ nop
53
  sub  sp, fp, #20
54
  ldmfd  sp, {r2, r3, fp, sp, lr}
55
  ldr  ip, [sp], #4
56
  subs  pc, lr, #4
57
.L8:
58
  .align  2
59
.L7:
60
  .word  -536788992
61
  .word  temp.4694
62
  .word  -4048
63
  .size  pwm0ISR, .-pwm0ISR
64
.L12:
65
  .align  2
66
.L11:
67
  .word  1073725440
68
  .word  -536690688
69
  .word  -536838032
70
  .word  -536838132
71
  .word  -536838120
72
  .word  -536838124
73
  .word  -536838084
74
  .word  -536838140
75
  .word  -536788980
76
  .word  -536788968
77
  .word  -536788972
78
  .word  -536788988
79
  .word  -4084
80
  .word  -4080
81
  .word  -3564
82
  .word  -3820
83
  .word  pwm0ISR
84
  .word  _impure_ptr
85
  .size  TLC5940_init, .-TLC5940_init
86
  .bss
87
  .align  2
88
temp.4694:
89
  .space  4
90
  .ident  "GCC: (GNU Tools for ARM Embedded Processors) 5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]"

von Thorsten E. (bluescreen)


Lesenswert?

Es geht immer so weiter. Irgendwas scheint an meiner Konfiguration des 
gcc Murks zu sein. Nun habe ich einen Crash sogar ganz ohne ISR. Und 
zwar hier:
1
#define S0SPCR (*(volatile unsigned short *)0xE0020000)
2
#define S0SPCR_CPHA 0x8
3
#define S0SPCR_CPOL 0x10
4
#define S0SPCR_MSTR 0x20
5
#define S0SPDR (*(volatile unsigned short *)0xE0020008)
6
7
// initialize SPI interface
8
unsigned short dummy;
9
PINSEL0 = (PINSEL0 & ~(3 << 12)) | (1 << 12);
10
PINSEL0 = (PINSEL0 & ~(3 << 10)) | (1 << 10);
11
PINSEL0 = (PINSEL0 & ~(3 << 8)) | (1 << 8);
12
13
S0SPCCR = 64;          // SPI Clock Divisor
14
S0SPCR  = S0SPCR_MSTR | S0SPCR_CPOL | S0SPCR_CPHA; // SPI Config Register
15
dummy   = S0SPDR;      // Clear Read Data Register CRASH
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

von W.S. (Gast)


Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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.

von Lothar (Gast)


Lesenswert?

W.S. schrieb:
> doch zuerst mal mit dem Keil versuchen

Besser mit IAR. Hier gibt es ein LPC2148 Board mit fertigen Demos die 
auf jeden Fall laufen:

https://www.olimex.com/Products/ARM/NXP/LPC-P2148/

IAR runterladen und dann die Kickstart Version aktivieren die 32K Code 
Limit sollten reichen:

https://www.iar.com/iar-embedded-workbench/

von W.S. (Gast)


Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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?

von Thorsten E. (bluescreen)


Lesenswert?

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:
1
(gdb) disas 0
2
Dump of assembler code for function __reset:
3
   0x00000000 <+0>:                     ; <UNDEFINED> instruction: 0xffffffff
4
   0x00000004 <+4>:                     ; <UNDEFINED> instruction: 0xffffffff
5
   0x00000008 <+8>:                     ; <UNDEFINED> instruction: 0xffffffff
6
   0x0000000c <+12>:                    ; <UNDEFINED> instruction: 0xffffffff
7
   0x00000010 <+16>:                    ; <UNDEFINED> instruction: 0xffffffff
8
   0x00000014 <+20>:                    ; <UNDEFINED> instruction: 0xffffffff
9
   0x00000018 <+24>:                    ; <UNDEFINED> instruction: 0xffffffff
10
   0x0000001c <+28>:                    ; <UNDEFINED> instruction: 0xffffffff
11
End of assembler dump.
12
(gdb) stepi
13
0x00000004 in __reset ()
14
(gdb) disas 0
15
Dump of assembler code for function __reset:
16
   0x00000000 <+0>:     ldr     r4, [pc, #52]   ; 0x3c <fiq_handler_address>
17
=> 0x00000004 <+4>:     mov     r5, #2
18
   0x00000008 <+8>:     str     r5, [r4]
19
   0x0000000c <+12>:    mov     r5, #3
20
   0x00000010 <+16>:    str     r5, [r4, #4]
21
   0x00000014 <+20>:    ldr     r2, [pc, #28]   ; 0x38 <irq_handler_address>
22
   0x00000018 <+24>:    mov     r3, #0
23
   0x0000001c <+28>:    swp     r0, r3, [r2]
24
End of assembler dump.

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:
1
0x0000001c in __reset ()
2
(gdb) stepi
3
ThumbEE -- incomplete support
4
0xfffffff8 in ?? ()

von Thorsten E. (bluescreen)


Angehängte Dateien:

Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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?

von W.S. (Gast)


Lesenswert?

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.

von Thorsten E. (bluescreen)


Angehängte Dateien:

Lesenswert?

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:
1
demo2148_blink_flash/main.c:58: undefined reference to `__aeabi_uidiv'

Deshalb habe ich ein paar Linker Parameter aus meinem anderen Projekt 
genommen.
Statt
1
$(LD) -Map main.map -Tdemo2148_blink_flash.cmd -o main.elf  crt.o main.o uart.o

nun
1
$(CC) crt.o main.o uart.o -o main.elf -Wl,-Map=main.map,--cref -Tdemo2148_blink_flash.cmd --specs=nosys.specs

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.

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Thorsten E. (bluescreen)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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 alle ARM-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.

von Thorsten E. (bluescreen)


Lesenswert?

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

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.