Forum: Mikrocontroller und Digitale Elektronik MSP430 - Interrupt Problem


von Stephan S. (stephan1980)


Lesenswert?

Hallo!

Zuerst einmal: ich benutze CCE v3.1 und will dort das Flash Monitor 
Programm von Texas Instruments zum Laufen kriegen (ist eigentlich für 
den IAR geschrieben).
Das Programm besteht aus einem C- und einem Assembler-Code (der 
eigentliche Flash Monitor).
Nun habe ich soweit alle Befehle umgeschrieben, so dass beide Programme 
einzeln (!) unter CCE laufen (und zumindest theoretisch funktionieren 
g). Doch sobald ich beide Codes in einem Projekt habe, kriege ich 
Fehler, weil beide (Assembler und C) scheinbar Speicher für die 
Interrupt Vektoren reservieren und daher diese nicht korrekt 
angesprochen werden können.
Hier habe ich den Rat bekommen, ein link map file zu erzeugen, das mir 
anzeigt, was wieviel Speicher benötigt und siehe da, die Interrupt 
Vektoren für TimerA (int05) und UART1 (int03) sowie der Reset Vektor 
brauchen 4 Byte anstatt 2. Laut Anleitung muss man dies im Linker 
Command File einfach ändern, was ich auch gemacht habe (sprich die Länge 
der entsprechenden Vektoren auf 4 Bytes erhöht und dann noch die 
jeweiligen Startadressen anpassen, da sie sich sonst überlappen würden).
Nun kriege ich zwar keine Fehler mehr, aber beim Debuggen springt der 
PC, wenn der Interrupt ausgelöst wird ins Nichts!?

Nun hab ich noch am Ende der msp430x44x.h Header Datei folgende Zeilen:
1
#define BASICTIMER_VECTOR       (0 * 1u)      /* 0xFFE0 Basic Timer */
2
#define PORT2_VECTOR            (1 * 1u)      /* 0xFFE2 Port 2 */
usw.
Also dachte ich mir, ich muss da den Offset auch ändern, schließlich ist 
der TimerA1 Vektor ja jetzt länger:
1
#define TIMERA1_VECTOR          (5 * 1u)     /* 0xFFEA Timer A CC1-2, TA */
2
#define TIMERA0_VECTOR          (7 * 1u)     /* 0xFFEC Timer A CC0 */
3
#define ADC12_VECTOR            (8 * 1u)     /* 0xFFEE ADC */
usw.
Leider klappt das auch nicht. Hat jemand eine Idee??

von Christian R. (supachris)


Lesenswert?

Also wenn du 4 Bytes auf dem Vektor unterbringen willst, hast du was 
falsch gemacht. Da ist für jeden Interrupt nur 2 Byte Platz. Und da 
ändert auch kein Linker-File etwas. Da scheint in deinem ASM was falsch 
zu sein, normal gehört ja da nur die Sprungadresse der entsprechenden 
ISR hin und sonst nix anderes.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die Hardware legt fest, wo die Interruptvektoren liegen und wie groß 
sie sind. Das kann man nicht nach belieben umdefinieren.

Interruptvektoren sind in einer Tabelle am oberen Ende des 
64K-Adressraumes im Flash gespeichert, ihre genaue Bedeutung ist im 
Datenblatt/User's Guide des jeweiligen MSP430-Derivates aufgelistet.

Dein Problem scheint zu sein, daß sowohl im Assemblerprogramm die 
Interruptvektortabelle mit Inhalt gefüllt wird als auch im C-Programm.

Es gibt aber nur eine, und --wie bereits gesagt--, was in ihr wo steht, 
ist durch den Prozessor vorgegeben.

Du musst also die Mischung C/Assembler irgendwie auseinander"tüddeln". 
Eine Möglichkeit bestünde darin, Interruptvektoren nur in einer der 
beiden Sprachen zu behandeln und gegebenenfalls aus dem Interrupthandler 
heraus den 'eigentlichen' Interrupthandler der anderen Sprache 
aufzurufen, der dann allerdings zur reinen Funktion degradiert werden 
muss.

von Stephan S. (stephan1980)


Lesenswert?

Hui, das ging aber schnell, Danke!

Hmmm...dann hab ich die Anleitung von TI wohl falsch verstanden:

http://tiexpressdsp.com/index.php?title=CCE_FAQ#What_does_the_CCE_linker_error:_.27placement_fails_for_object_.22xxx.22.27_mean_and_how_to_fix_it.3F

Kann mir dann jemand sagen, was die mit "the section allocation in the 
linker command file should be modified to avoid the error" dann meinen?

Irgendwie steh ich grad aufm Schlauch...hat aber vielleicht auch was mit 
der Magen-Darm-Grippe zu tun, die ich gerade hatte ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Der Artikel beschreibt nicht die ganz besondere Behandlung von 
Interruptvektortabellen und ist daher wenig hilfreich. Was dort 
beschrieben ist, darfst Du eben nicht machen.

von Stephan S. (stephan1980)


Lesenswert?

Naja gut, aber ich habe diesen Fehler "placement fails for object..." 
für eben '.int03' (UART1_RX), '.int05' (TIMERA1) und '.reset'

Aus diesem Grund habe ich ja obiges Problem, was wohl daran liegt, dass 
ich die Anleitung zum Beheben des Fehlers falsch verstanden habe...ich 
darf also nicht den Speicher ändern, sondern das Segment...aber wie?

Im Linker Command File steht folgendes:
1
SECTIONS
2
{
3
    .bss       : {} > RAM        /* GLOBAL & STATIC VARS              */
4
    .sysmem    : {} > RAM        /* DYNAMIC MEMORY ALLOCATION AREA    */
5
    .stack     : {} > RAM (HIGH) /* SOFTWARE SYSTEM STACK             */
6
    .text      : {} > FLASH      /* CODE                              */
7
    .cinit     : {} > FLASH      /* INITIALIZATION TABLES             */
8
    .const     : {} > FLASH      /* CONSTANT DATA                     */
9
    .cio       : {} > RAM        /* C I/O BUFFER                      */
10
    .pinit     : {} > FLASH      /* C++ CONSTRUCTOR TABLES            */
11
    .infoA     : {} > INFOA      /* MSP430 INFO FLASH MEMORY SEGMENTS */
12
    .infoB     : {} > INFOB
13
    .int00   : {} > INT00        /* MSP430 INTERRUPT VECTORS          */
14
    .int01   : {} > INT01
15
    .int02   : {} > INT02
16
    .int03   : {} > INT03
17
    .int04   : {} > INT04
18
    .int05   : {} > INT05
19
    .int06   : {} > INT06
20
    .int07   : {} > INT07
21
    .int08   : {} > INT08
22
    .int09   : {} > INT09
23
    .int10   : {} > INT10
24
    .int11   : {} > INT11
25
    .int12   : {} > INT12
26
    .int13   : {} > INT13
27
    .int14   : {} > INT14
28
    .reset   : {} > RESET         /* MSP430 RESET VECTOR               */ 
29
}

sowie:
1
MEMORY
2
{
3
    SFR                     : origin = 0x0000, length = 0x0010
4
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
5
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
6
    RAM                     : origin = 0x0200, length = 0x0800
7
    INFOA                   : origin = 0x1080, length = 0x0080
8
    INFOB                   : origin = 0x1000, length = 0x0080
9
    FLASH                   : origin = 0x1100, length = 0xEEE0
10
    INT00                   : origin = 0xFFE0, length = 0x0002
11
    INT01                   : origin = 0xFFE2, length = 0x0002
12
    INT02                   : origin = 0xFFE4, length = 0x0002
13
    INT03                   : origin = 0xFFE6, length = 0x0002
14
    INT04                   : origin = 0xFFE8, length = 0x0002
15
    INT05                   : origin = 0xFFEA, length = 0x0002
16
    INT06                   : origin = 0xFFEC, length = 0x0002
17
    INT07                   : origin = 0xFFEE, length = 0x0002
18
    INT08                   : origin = 0xFFF0, length = 0x0002
19
    INT09                   : origin = 0xFFF2, length = 0x0002
20
    INT10                   : origin = 0xFFF4, length = 0x0002
21
    INT11                   : origin = 0xFFF6, length = 0x0002
22
    INT12                   : origin = 0xFFF8, length = 0x0002
23
    INT13                   : origin = 0xFFFA, length = 0x0002
24
    INT14                   : origin = 0xFFFC, length = 0x0002
25
    RESET                   : origin = 0xFFFE, length = 0x0002
26
}

So, wie ist jetzt die Anweisung "... Here you can verify if the size of 
the .int09 section is larger than 0x2, and if so, the section allocation 
in the linker command file should be modified to avoid the error." zu 
verstehen?

von Christian R. (supachris)


Lesenswert?

Ich glaube du doktorst an einer völlig falschen Stelle herum. Du musst 
dafür sorgen, dass eine ISR immer nur einmal deklariert wird. Die 
Fehlermeldung lässt darauf schließen, dass du im ASM und im C jeweils 
die 3 ISRs definiert hast. Somit hat der Linker dann einen Konflikt, 
weil 2 (verschiedene) Sprungadressen in die Vektortabelle eingetragen 
werden sollen.
Das .reset benötigt sicher eine Sonderbehandlung. Entweder wirfst du es 
aus dem ASM raus, oder verbietest dem C-Compiler, die Reset-Routine 
anzulegen. In beiden Fällen muss man aber ganz genau wissen, was man 
macht. Die beiden anderen ISRs hast du ja selber in der Hand. Poste doch 
mal ein Zip mit allen Quelltexten.

von Stephan S. (stephan1980)


Angehängte Dateien:

Lesenswert?

Naja, der Witz ist doch soweit ich verstanden habe der, dass eben beide 
Programme selbstständig laufen können.
Der Asm Code ist der eigentliche Flash Monitor, der ja immer laufen 
können soll. Mit dem C Code Beispiel soll ja nur demonstriert werden, 
wie aus einem belibiegen Programm eben der flash monitor gestartet 
werden kann.

D.h. theoretisch muss ich im C-Code keinen USART nutzen und 
initialisieren, aber dann muss das der Asm Code machen...der braucht das 
ja.
Die Beispiele sind für den IAR Compiler gemacht und laufen da auch 
einwandfrei (hab mal die kostenlose Version installiert), ich muss es 
halt hier unter CCE zum Laufen kriegen.

von Christian R. (supachris)


Lesenswert?

Naja, dann hast du nicht richtig gelesen. In 3.2.1 des Manuals steht 
doch, dass du deinem C-Compiler beibringen musst, dass er die 
Interrupt-Vektoren an einer anderen stelle speichern soll als üblich. 
Wie das beim CCE dann aber geht, weiß ich nicht. Sollte aber recht 
einfach über das Linker-Script gehen. Deine C-Applikation hat dann 
völlig andere Interrupt-Vektoren, auf den originalen sitzt der Flash 
Monitor.

von Stephan S. (stephan1980)


Lesenswert?

Meinst du 3.2.1 aus "A Flash Monitor for the MSP420" (SLAA341) ?
Wenn ja, dann lese ich dort, dass man das "linker command file" 
modifizieren muss und der folgende Code dann entsprechend für den IAR 
Linker gedacht ist.
Oben habe ich doch aber schon den entsprechenden Auszug aus dem "linker 
command file" für den CCE gepostet aber es hieß, da darf ich nix dran 
ändern!?

Rufus t. Firefly wrote:
> Die Hardware legt fest, wo die Interruptvektoren liegen und wie groß
> sie sind. Das kann man nicht nach belieben umdefinieren.

Komischerweise mache ich aber doch genau das, wenn ich nach 3.2.1 
vorgehe und das funktioniert im IAR einwandfrei!?

Wenn Du ein anderes 3.2.1 meinst, dann vergiss, was ich geschrieben hab 
:-)

von Christian R. (supachris)


Lesenswert?

Ja, das meine ich. Du musst die Position der Interrupt-Vektoren 
verändern, aber nur die Position, nicht die Größe. Die bleibt nach wie 
vor bei 2 Byte pro Interrupt. Wenn du die Adressen verändert hast, kann 
das ASM Programm durch die org Anweisung die ISRs direkt in der 
originalen Position platzieren, und der Linker des C-Programm platziert 
die ISRs deines User-Programms dann an der neuen Position. Dann darf 
auch keine Fehlermeldung kommen, da der Linker ja für jedes extra 
Positionen hat, und sich nix überlappt. Du musst auch die Größe der TXT 
Section anpassen, denn der Monitor braucht seinen komplett eigenen 
Speicherbereich. Ebenso die Data Section für die Variablen. Aber die 
Größe der Interrupt-Vektor-Tabelle bleibt bei 32 Byte für die 16 
Vektoren und 2 Byte für den Reset.

von Stephan S. (stephan1980)


Angehängte Dateien:

Lesenswert?

So, nachdem ich die Magen-Darm-Grippe überstanden habe, habe ich 
immernoch Kopfschmerzen ;-)

Also wenn ich das jetzt richtig verstanden habe, habe ich durch das 
modifizierte Linker Command File eine andere Interrupt Vektor Tabelle 
für meinen C-Code als für den Assembler Code, in dem ja (siehe Anhang) 
am Ende die "originalen" Adressen benutzt werden.

Soweit so gut, aber mein Problem ist ja jetzt, das ganze mit dem CCE zu 
machen. Da gibt es keine solche Speichersegmentkontrolle:
"The CCE Asm430 assembler does not support any of the IAR A430 segment 
control directives such as ORG, ASEG, RSEG, and COMMON."
"To allocate code and data sections to specific addresses with the CCE 
assembler, it is necessary to create/use memory sections defined in the 
linker command files." (D.2 in SLAU157H)
In dem Beispiel dort wird dann anstelle von
1
ORG 0FFF2h
2
DW  TA0_ISR
die Information aus dem Linker Command File benutzt:
1
 .sect ".int09"
2
 .short TA0_ISR

Das Linker Command File wird doch aber auch für/vom C-Code benutzt! Wie 
kann ich hier also für C und Assembler "getrennt" die Interrupt Vektor 
Tabelle definieren?
Wenn jemand ne Idee hat...
Ich hirne einfach mal weiter. Wenn ich was finde, poste ichs natürlich!

von Christian R. (supachris)


Lesenswert?

Achso....da liegt das Problem. Nun ja, dann wirst du diese (eh nicht 
besonders elegante) Methode mit dem CCE nicht benutzen können. Schreib 
dir einen eigenen kleinen Bootloader und gut ist. Das hätte bisher 
weniger Zeit in Anspruch genommen als das hier auf Krampf zu versuchen. 
Ich hab mir auch einen "Bootloader" gemacht, da kann ich den MSP430 über 
Funk mit dem CC2420 Updaten (außer den Funkloader natürlich)

von Stephan S. (stephan1980)


Lesenswert?

Naja, ich sitze hier als Student an einem Firmenprojekt und soll das 
halt so machen...hatte vorher noch nur mal einen PIC16F690 programmiert 
und sonst keine Erfahrung mit der ganzen Materie.

Bis ich mal dahintergestiegen bin, was das Programm überhaupt auf dem µC 
macht, wie der µC überhaupt und das alles funktioniert, hat ja schon 
gedauert. Sitz da schon fast 2 Wochen dran.

Also gut, ich werd mal schauen, wie ich dass meinem Betreuer beibringen 
kann...

Danke trotzdem für die tolle und schnelle Hilfe!!!
Hab doch einiges gelernt!

von Christian R. (supachris)


Lesenswert?

Wie muss man denn beim CCE3 Assembler die Interrupts deklarieren? 
Vielleicht kann man ja einfach noch einen 2. 16er Block erstellen, und 
die dann meinetwegen .int109 statt .int09 nennen. Genauso dann im 
Linker-Command File.

von Stephan S. (stephan1980)


Lesenswert?

supachris, Du bist SUPER!!!

So gehts: im Linker Command File einen zweiten Satz Interrupt Vektoren 
erstellen und die passenden Segmente dazu (hab sie so benannt wie Du es 
vorgeschlagen hast ;-) ). Natürlich noch den Flash-Speicher anpassen 
(Länge muss gekürzt werden).
Dann einfach im Assembler Code die "neuen" Vektoren benutzen:
1
  .sect  ".int100"  
2
  .short  Int_Priority_0  
3
  .sect   ".int101"  
4
  .short  Int_Priority_1
usw.
Und schon laufen C- und Assembler im selben Projekt.
Ich hatte noch erst Probleme, vom Assembler in den C-Code zurück zu 
springen, weil beim IAR einfach der Reset-Vektor geladen wird. Da beim 
CCE die ganze Sache vertauscht ist (hier benutzt der Assembler Code die 
"verschobene" Vektor Tabelle und der C-Code die "originale") musste ich 
anstatt 0xFBFE (reset vector vom Assembler) einfach 0xFFFE in den PC 
schreiben und schon hats geklappt!
Ich kann jetzt wie beim IAR zwischen Applikation (C-Programm) und 
Monitor (Assembler) schön hin und her springen, die Checksum berechnen, 
den Speicher anzeigen lassen etc!!!

Jetzt ist nur noch ein kleines Schönheitsproblem:
Im Assembler-Code sind wie folgt Zeichenfolgen gespeichert:
1
CmdTable:  .byte  "CDEGIU"  
2
Prompt:    .byte  "\r\n?"    
3
Pass:    .byte  "PW?"    
4
CRLF    .byte  "\r\n"    
5
ProgErr    .byte  "ERR\r\n"  
6
NotBlank  .byte  "NB\r\n"  
7
FilePrompt  .byte  "@?"

Diese werden je nach Bedarf Zeichen für Zeichen via UART an den 
Hyperterminal gesendet. Beim IAR funktioniert das super, \r\n läßt den 
Cursor an den Zeilenanfang einer neuen Zeile springen und wenn die 
Zeichenfolge vorbei ist kommt ein "Null"-Zeichen (einfach 0x00), so dass 
das Senden abgebrochen wird.
Beim CCE funktioniert zum einen \r\n nicht (die Zeichen werden einfach 
mit ausgegeben) und zum anderen gibt es anscheinend nicht automatisch 
ein Null-Zeichen am Ende eines solchen "Strings", so dass die Funktion 
ewig weiter sendet.
Das zweite Problem habe ich gelöst, indem ich einfach nach jeder 
Zeichenfolge ein .byte 0 angehängt habe. Klappt auch, ist aber 
vielleicht nicht das eleganteste.
Aber warum funktioniert \r\n nicht?
Beim IAR sendet der MSP doch auch einfach nur diese Zeichen via UART!?

Soll ich die Frage vielleicht in einem neuen Post stellen???
(Geht ja immerhin um was ganz anderes jetzt...)

Viele Grüße und vielen, vielen Dank!

Stephan

von Christian R. (supachris)


Lesenswert?

Na da hättest du doch selber drauf kommen können ;)

Das Problem an \r\n ist eventuell, dass der CCE Assembler das wieder 
nicht korrekt versteht. Der nimmt das offensichtlich als einzelne 
Zeichen. Auch da müsstest du mal im User Guide schauen, oder bei TI 
anfragen. Dass das Null-Byte am Ende automatisch ist, ist ebenso 
Assembler-abhängig. Manche machen das, manche nicht.

von Stephan (Gast)


Lesenswert?

Hab grad hier im Forum ein Steuerzeichen.pdf gefunden, wo ausführlich 
drin steht, welche Zahl für Zeilenvorschub und welche für Wagenrücklauf 
steht.
naja, jetzt benutze ich anstelle von
1
 Prompt:     DB  "\r\n?"
"einfach"
1
Prompt:   .byte   10  ;ASCII Code: 0x0A = Zeilenvorschub (Line feed LF)
2
          .byte   13  ;ASCII Code: 0x0D = Wagenrücklauf (carriage return CR)
3
          .string "?"    
4
          .byte    0   ;Null character

Sieht jetzt gut aus! ;-)

Danke nochmal!

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.