Hallo Experten,
ich habe gerade begonnen mit dem MSP430F1611 in Assembler zu
programmieren. Ich benutze unter Linux den msp430-gcc und den ddd mit
msp430-debugger. Ich habe das OLIMEX MSP430-P1611 Eval Board.
Ich möchte den 32,768 KHz Quartz für MCLK und ACLK 1:1 verwenden, um mit
dem TimerA im "count up to TACCR0" mode jede Sekunde einen Interrupt
auszulösen. Hat der TimerA den Wert in TACCR0 erreicht, setzt die
zugehörige ISR (TIMERA0_ISR) im Register R13 ein Flag. Der Mainloop
fragt ständig das Flag ab und toggelt eine LED an Port 6 bit 0 wenn das
Flag gesetzt wurde. Anschließend wird das Flag wieder gelöscht. Alle
anderen ISRs setzen entsprechend ihrer Priorität Bits in R14. Eigentlich
ganz einfach, oder??? Aber es klappt nicht!
Problem:
Wenn der das Zählerregister (TAR) vom TimerA den in TACCR0 vorgegeben
Soll-Wert (hier testweise 0xA) erreicht, springt der Programmcounter auf
den Wert 0xffff . Dann verabschiedet sich das Programm, klar!
Der MCLK läuft mit ca. 60kHz statt mit 32kHz. Der ACLk läuft mit der
gleichen Frequenz wie der MCLK aber nur mit einigen 100mV Amplitude.
Was mache ich falsch?? Hoffentlich könnt Ihr mir helfen!
Stephan
Hier der Assembler Code:
#include <signal.h>
#include <io.h>
#include <msp430x16x.h>
#define P6OUT 0x35
#define P6DIR 0x36
#define P6SEL 0x37
#define P5DIR 0x32
#define P5SEL 0x33
.section .text
;-----------------------------------------------------------------------
------
; Program RESET
;-----------------------------------------------------------------------
------
RESET: MOV #__stack,R1 ; Initialize stackpointer
CALL #Setup ; basic hardware setup
;-----------------------------------------------------------------------
------
; Mainloop
;-----------------------------------------------------------------------
------
Mainloop: BIT #0x01,R13 ; Test if flag is set. (set after INT)
JZ Mainloop ; Loop if flag is not set
BIT.b #0x01,&P6OUT ; Test if LED is off (P6.0 = 1)
JNZ Ledon ; Jump to Ledon
Ledoff: BIS.b #0x01,&P6OUT ; Turn LED off
BIC #0x01,R13 ; Clear flag
JMP Mainloop ; Wait for next INTERRUPT
Ledon: BIC.b #0x01,&P6OUT ; Turn LED on
BIC #0x01,R13 ; Clear flag
JMP Mainloop ; Wait for next INTERRUPT
;-----------------------------------------------------------------------
------
; Setup: Configure Modules and Control Registers
;-----------------------------------------------------------------------
------
Setup: MOV #WDTPW+WDTHOLD,&WDTCTL ; Stop Watchdog Timer
BIS.b #0x38,&P5SEL ; Select I/O for P5.4-6
BIS.b #0x38,&P5DIR ; Set output direction for P5.4-6
BIC.b #0x01,&P6SEL ; select I/O-function for P6.0
BIS.b #0x01,&P6DIR ; set P6.0 direction to output
BIC.b #0x01,&P6OUT ; clear P6.0 (turn LED on)
CLR R13 ; clear R13 incl. flag
CLR R14 ; clear R14 for Interrupt source detect
MOV #TASSEL0+TACLR, &TACTL ; ACLK for Timer_A.
BIS #CCIE,&CCTL0 ; Enable CCR0 interrupt.
MOV #0xA,&CCR0 ; load CCR0 with 10.
; MOV #0x7FFF,&CCR0 ; load CCR0 with 32,767.
BIS.b #SELM1+SELM0,&BCSCTL2 ; set MCLK source to LFXT1CLK
BIS #MC0,&TACTL ; start TA in "up to CCR0" mode
EINT ; Enable interrupts
RET ; Done with setup
;-----------------------------------------------------------------------
------
; Interrupt service routines:
;-----------------------------------------------------------------------
------
DACDMA_VECTOR_ISR: BIS #0x8000,R14 ; 0xFFE0 DAC12/DMA
RETI
PORT2_VECTOR_ISR: BIS #0x4000,R14 ; 0xFFE2 Port 2
RETI
USART1TX_VECTOR_ISR: BIS #0x2000,R14 ; 0xFFF4 USART 1 Transmit
RETI
USART1RX_VECTOR_ISR: BIS #0x1000,R14 ; 0xFFF6 USART 1 Receive
RETI
PORT1_VECTOR_ISR: BIS #0x800,R14 ; 0xFFE8 Port 1
RETI
TIMERA1_ISR: BIS #0x400,R14 ; 0xFFEA Timer A CC1-2, TA
RETI
TIMERA0_ISR: BIS #0x01,R13 ; 0xFFEC Timer A CC0
RETI
ADC12_VECTOR_ISR: BIS #0x100,R14 ; 0xFFEE ADC
RETI
USART0TX_VECTOR_ISR: BIS #0x80,R14 ; 0xFFF0 USART 0 Transmit
RETI
USART0RX_VECTOR_ISR: BIS #0x40,R14 ; 0xFFF2 USART 0 Receive I2C tx/rx
RETI
WDT_VECTOR_ISR: BIS #0x20,R14 ; 0xFFF4 Watchdog Timer
RETI
COMPARATORA_VECTOR_ISR: BIS #0x10,R14 ; 0xFFF6 Comparator A
RETI
TIMERB1_VECTOR_ISR: BIS #0x08,R14 ; 0xFFF8 Timer B CC1-2, TB
RETI
TIMERB0_ISR: BIS #0x04,R14 ; 0xFFFA TIMER B CC0
RETI
NMI_ISR: BIS #0x02,R14 ; 0xFFFC Non maskable
RETI
;-----------------------------------------------------------------------
------
; MSP430F1611 interrupt vector table
;-----------------------------------------------------------------------
------
.section .vectors
.org DACDMA_VECTOR,0xFF
.word DACDMA_VECTOR_ISR ; 0xFFE0 DAC12/DMA
.org PORT2_VECTOR,0xFF
.word PORT2_VECTOR_ISR ; 0xFFE2 Port 2
.org USART1TX_VECTOR,0xFF
.word USART1TX_VECTOR_ISR ; 0xFFF4 USART 1 Transmit
.org USART1RX_VECTOR,0xFF
.word USART1RX_VECTOR_ISR ; 0xFFF6 USART 1 Receive
.org PORT1_VECTOR,0xFF
.word PORT1_VECTOR_ISR ; 0xFFE8 Port 1
.org TIMERA1_VECTOR,0xFF
.word TIMERA1_ISR ; 0xFFEA Timer A CC1-2, TA
.org TIMERA0_VECTOR,0xFF
.word TIMERA0_ISR ; 0xFFEC Timer A CC0
.org ADC12_VECTOR,0xFF
.word ADC12_VECTOR_ISR ; 0xFFEE ADC
.org USART0TX_VECTOR,0xFF
.word USART0TX_VECTOR_ISR ; 0xFFF0 USART 0 Transmit
.org USART0RX_VECTOR,0xFF
.word USART0RX_VECTOR_ISR ; 0xFFF2 USART 0 Receive I2C tx/rx
.org WDT_VECTOR,0xFF
.word WDT_VECTOR_ISR ; 0xFFF4 Watchdog Timer
.org COMPARATORA_VECTOR,0xFF
.word COMPARATORA_VECTOR_ISR ; 0xFFF6 Comparator A
.org TIMERB1_VECTOR,0xFF
.word TIMERB1_VECTOR_ISR ; 0xFFF8 Timer B CC1-2, TB
.org TIMERB0_VECTOR,0xFF
.word TIMERB0_ISR ; 0xFFFA TIMER B CC0
.org NMI_VECTOR,0xFF
.word NMI_ISR ; 0xFFFC Non maskable
.org RESET_VECTOR,0xFF
.word RESET ; POR, external RST, Watchdog
>Ich möchte den 32,768 KHz Quartz für MCLK und ACLK 1:1 verwenden, um mit>dem TimerA im "count up to TACCR0" mode jede Sekunde einen Interrupt>auszulösen.
Ich würde MCLK nicht auf 32,768kHz setzen, sondern auf DCO belassen.
Die CPU mit 32,768kHz zu takten bringt keinen Vorteil!
ACLK für TMR_A ist OK
>Der MCLK läuft mit ca. 60kHz statt mit 32kHz. Der ACLk läuft mit der>gleichen Frequenz wie der MCLK aber nur mit einigen 100mV Amplitude.
Wo gemessen? An P5.4 und P5.6?
Auch mal an XOUT direkt gemessen?
>BIS.b #0x38,&P5SEL ; Select I/O for P5.4-6>BIS.b #0x38,&P5DIR ; Set output direction for P5.4-6
Damit wählst Du aber P5.3-P5.5 aus!
BIS.b #0x70,... sollte funktionieren
>.org TIMERA0_VECTOR,0xFF>.word TIMERA0_ISR ; 0xFFEC Timer A CC0
Ich kenne mich mit Deiner tool-chain nicht aus,
aber warum steht bei .org ein 0xFF dahinter?
Ist in TIMERA0_VECTOR nur das Low-Byte (0xEC) definiert?
Nicht dass Deine Vektoren ins Nirwana zeigen und der µC deshalb
abschmiert?!
Generell:
-Vcc geprüft?
-eventuell beim Setup kleine Warteschleife, um ACLK stabilisieren zu
lassen (kann u.U. mehrere 100ms dauern!!!)
Hallo Stefan,
vielen Dank für Deine Tipps. Ich werde sie heute Abend eingehend prüfen.
Mit den Ports P5 hast Du natürlich recht! Es muss 0x70 statt 0x38 für
P5.4 - P5.6 heißen. Habe das gerade auch geprüft, jetzt stimmt die
Amplitude von ACLK!
Das mit den Interrupt-Vektoren (0xFF) kommt mir auch komisch vor. Ich
habe das aus einem TI Sample Code. Im Assembler Listing baut er es
meiner Meinung aber richtig zusammen. Ich poste das später gleich mal.
Habe auch schon den Stackinitialisierungsmakro __stack im Verdacht
gehabt. Der initialisiert den Stack mit 0x3900. Laut Datenblatt geht der
RAM Bereich von 0x1100 bis 0x38FF. Tja!? Ich habe ihn schon auf 0x3800
initialisiert, hilft aber nichts.
Muß ich den DCO dann noch irgendwie kalibrieren? Oder kann der mit den
Defaultwerten laufen?
Das mit der Warteschleife für ACLK-Stabilisierung probiere ich gleich
mal aus!
Später mehr, vielen Dank nochmals.
Gruß
Stephan
@ Stephan Bode (Gast)
>auszulösen. Hat der TimerA den Wert in TACCR0 erreicht, setzt die>zugehörige ISR (TIMERA0_ISR) im Register R13 ein Flag. Der Mainloop>fragt ständig das Flag ab und toggelt eine LED an Port 6 bit 0 wenn das>Flag gesetzt wurde. Anschließend wird das Flag wieder gelöscht.
Warum toggelst du die LED nicht in der ISR?
>Der MCLK läuft mit ca. 60kHz statt mit 32kHz. Der ACLk läuft mit der>gleichen Frequenz wie der MCLK aber nur mit einigen 100mV Amplitude.
???
Lässt du MCLK ausgeben? Dann muss dort ein solides Digitalsignal
rauskommen.
Mit ASM kenn ich mich auf dem MSP nicht aus.
>gehabt. Der initialisiert den Stack mit 0x3900. Laut Datenblatt geht der>RAM Bereich von 0x1100 bis 0x38FF.
Passt schon. Der Stack wird über Predekrement adressier.
>Muß ich den DCO dann noch irgendwie kalibrieren? Oder kann der mit den>Defaultwerten laufen?
Sicher. Wozu brauchst du einen hochpräzisen Takt zum LED toggeln?
MfG
Falk
>Das mit den Interrupt-Vektoren (0xFF) kommt mir auch komisch vor. Ich>habe das aus einem TI Sample Code.
Der TI Sample Code lautet aber:
1
ORG0FFECh;Timer_A0Vector
2
DWTA0_ISR;
Ich würde mir die Definition von TIMERA0_VECTOR bzw. die Doku zu .org
für Dein Tool nochmal genauer anschauen, ob das
1
.orgTIMERA0_VECTOR,0xFF
wirklich das macht, was es soll!
>Der initialisiert den Stack mit 0x3900. Laut Datenblatt geht der>RAM Bereich von 0x1100 bis 0x38FF
0x3900 stimmt schon. Der Stack wird von oben her "befüllt".
Zuerst wird dekrementiert (beim 1. Mal bist Du dann richtig bei 0x38FF
oder kleiner) und dann wird auf den Stack geschrieben.
>Muß ich den DCO dann noch irgendwie kalibrieren? Oder kann der mit den>Defaultwerten laufen?
Für Dein "simples" Beispiel kann der DCO so bleiben, wie er nach dem
Reset voreingestellt ist (ca. 1MHz). Wenn Du aber z.B. noch eine UART
brauchst, oder einen zweiten genauen Timer (der vom DCO getaktet wird),
dann solltest Du den DCO immer mal wieder auf die 32,768kHz
synchronisieren. Gibt's auch Bsp. von TI. Bei Bedarf nochmal nachfragen!
>Das mit der Warteschleife für ACLK-Stabilisierung probiere ich gleich>mal aus!
Das kann nicht schaden ;-)
Hat TI übrigens auch im Bsp. gemacht.
Hallo,
@ Falk: Natürlich hätte ich die LED auch in der ISR toggeln können. Ich
will mir nur gleich angewöhnen, flags in der ISR zu setzen, und die
Hauptarbeit im Mainloop zu erledigen. Mir fällt aber gerade ein, dass
die ISRs nicht reentrant sind, sofern man nicht das GIE manuell
verändert, die ISR beliebig vollpacken, oder? Es sei denn, ich möchte in
einem best. Zeitintervall Interrupts haben, dann sollte die ISR
Abarbeitung nicht länger als das Zeitintervall dauern.
Momentan läuft die CPU nur im Debugger, dann sehe ich auch einen
sauberen MCLK auf dem Oszi. Danke an Euch für den Tipp mit der
Predekrementadressierung des Stack, das hatte ich überlesen! Ich weiß,
dass ich zum LED toggeln keinen hochpräzisen Clock noch Flags in den
ISRs benötige, aber es soll ja auch nicht nur beim toggeln bleiben :-)
@ Stefan: Ich habe mich hauptsächlich an den im www.mikrocontroller.net
angegebenen Beispielen orientiert unter
http://www.mikrocontroller.net/articles/MSPGCC findet man unter "MSPGCC
Beispiele & Appnotes" den link auf ein CVS Repository:
http://mspgcc.cvs.sourceforge.net/mspgcc/examples/
Dort findet man die TI Beispiele SLAA* oder SLAC* wieder. Die Beispiele
für die IAR workbench und CCES von der TI homepage www.msp430.com
verwenden eine Syntax, die der msp430-gcc nicht versteht. In diesen
Assembler files findet sich z.B. keine ".section .text" Anweisung.
Kommentiere ich in meinem assembler code die .sections aus, streikt der
msp430-gcc. Auch mit ORG 0FFECh bzw. DW kommt er nicht klar und meldet:
msp430-gcc -g -O2 -mmcu=msp430x1611 -D_GNU_ASSEMBLER_ -nostartfiles
-nostandartlibs main.S -o main
main.S: Assembler messages:
main.S:104: Error: unknown opcode `org'
main.S:105: Error: unknown opcode `dw'
make: *** [main] Fehler 1
bzw.:
main.S:104: Error: attempt to move .org backwards
die Doku zum gnu assembler gas, der meiner Meinung nach hinter dem
msp430-gcc bzw. msp430-as steckt sagt folgendes zur .org Direktive:
------------------------------------------------------------------------
---
.org new-lc , fill
.org will advance the location counter of the current section to new-lc.
new-lc is either an absolute expression or an expression with the same
section as the current subsection. That is, you can't use .org to cross
sections: if new-lc has the wrong section, the .org directive is
ignored. To be compatible with former assemblers, if the section of
new-lc is absolute, will issue a warning, then pretend the section of
new-lc is the same as the current subsection.
.org may only increase the location counter, or leave it unchanged; you
cannot use .org to move the location counter backwards.
Because tries to assemble programs in one pass new-lc may not be
undefined. If you really detest this restriction we eagerly await a
chance to share your improved assembler.
Beware that the origin is relative to the start of the section, not to
the start of the subsection. This is compatible with other people's
assemblers.
When the location counter (of the current subsection) is advanced, the
intervening bytes are filled with fill which should be an absolute
expression. If the comma and fill are omitted, fill defaults to zero.
nachzulesen bei:http://www.cs.utah.edu/dept/old/texinfo/as/as.html#SEC90
------------------------------------------------------------------------
---
So sieht mein Assembler listing der Interrupttabelle aus (erzeugt mit
msp430-objdump -DSt main > main.lst:
0000ffe0 <_vectors_end-0x20>:
ffe0: 60 40 interrupt service routine at 0x4060
ffe2: 66 40 interrupt service routine at 0x4066
ffe4: 6c 40 interrupt service routine at 0x406c
ffe6: 72 40 interrupt service routine at 0x4072
ffe8: 78 40 interrupt service routine at 0x4078
ffea: 7e 40 interrupt service routine at 0x407e
ffec: 84 40 interrupt service routine at 0x4084
ffee: 88 40 interrupt service routine at 0x4088
fff0: 8e 40 interrupt service routine at 0x408e
fff2: 94 40 interrupt service routine at 0x4094
fff4: 9a 40 interrupt service routine at 0x409a
fff6: a0 40 interrupt service routine at 0x40a0
fff8: a6 40 interrupt service routine at 0x40a6
fffa: aa 40 interrupt service routine at 0x40aa
fffc: ae 40 interrupt service routine at 0x40ae
fffe: 00 40 interrupt service routine at 0x4000
So ist es doch richtig, oder?
folgendes Setup habe ich jetzt:
------------------------------------------------------------------------
---
Setup: MOV #WDTPW+WDTHOLD,&WDTCTL ; Stop Watchdog Timer
BIS.b #0x70,&P5SEL ; Select I/O for P5.4-6
BIS.b #0x70,&P5DIR ; Set output direction for P5.4-6
BIC.b #0x01,&P6SEL ; select I/O-function for P6.0
BIS.b #0x01,&P6DIR ; set P6.0 direction to output
BIC.b #0x01,&P6OUT ; clear P6.0 (turn LED on)
CLR R13 ; clear R13 incl. flag
CLR R14 ; clear R14 for Interrupt source detect
MOV #TASSEL0+TACLR, &TACTL ; ACLK for Timer_A.
BIS #CCIE,&CCTL0 ; Enable CCR0 interrupt.
MOV #0xA,&CCR0 ; load CCR0 with 10.
; MOV #0x7FFF,&CCR0 ; load CCR0 with 32,767.
BIS #MC0,&TACTL ; start TA in "up to CCR0" mode
EINT ; Enable interrupts
RET ; Done with setup
------------------------------------------------------------------------
---
Der ACLK hat auf dem OSZI ca. 7µs high level und fast 10µs low level.
Das macht etwa 58,8kHz. Amplitude ist etwa 3,3V. Der MCLK läuft mit
~1MHz und 3,3V schön symmetrisch. Da ist doch etwas nicht in Ordnung,
oder? Da ich das Olimex Board habe, habe ich mir über
Spannungsversorgung keine großen Sorgen gemacht.
Mit obigem Setup, zählt der Zähler überhaupt nicht mehr, ich kann im
Einzelschrittmodus mit dem Debugger durch die Main-Schleife steppen,
ohne das ein Interrupt kommt. Lasse ich den debugger laufen mit
Continue, ist kurz danach der MCLK aus. Das kann doch nicht so schwer
sein, oder? Was meint Ihr?
Stephan
@ Stephan Bode (Gast)
>@ Falk: Natürlich hätte ich die LED auch in der ISR toggeln können. Ich>will mir nur gleich angewöhnen, flags in der ISR zu setzen, und die>Hauptarbeit im Mainloop zu erledigen. Mir fällt aber gerade ein, dass
Gute Einstellung! Hast wohl den Artikel Interrupt gelesen? ;-)
>die ISRs nicht reentrant sind, sofern man nicht das GIE manuell>verändert, die ISR beliebig vollpacken, oder? Es sei denn, ich möchte in
???
Interrupts sind eigentlich nie reentrant. Ein reentranter Aufruf wäre
ein Programmier/Timingfehler.
>ISRs benötige, aber es soll ja auch nicht nur beim toggeln bleiben :-)
Dann nimm eine Quarz am Oszillator.
>.org may only increase the location counter, or leave it unchanged; you>cannot use .org to move the location counter backwards.
Na dann schreib das .org eben WIRKLICH ans Ende deines Quellcodes.
>So ist es doch richtig, oder?
Bin ich mir nicht sicher. Dort müsste doch DIREKT der Sprung in deine
Routine drinstehen, bzw die Adresse.
>Der ACLK hat auf dem OSZI ca. 7µs high level und fast 10µs low level.>Das macht etwa 58,8kHz. Amplitude ist etwa 3,3V. Der MCLK läuft mit
???
Wenn ACLK vom 32k Quarz kommt, dann müssen da auch 32kHz rauskommen,
auch recht nahe an 50% Duty Cycle. Per default wird ja der 32k Quarz
genutz. Hoffentlich stellts du dann nicht extra was falsches ein.
>Continue, ist kurz danach der MCLK aus. Das kann doch nicht so schwer>sein, oder? Was meint Ihr?
Eigentlich nicht. Stell mal gar nix an den Ozillatoreinstellungen rum,
aktiviere nur die Ausgabe von MCLK und ACLK an den Pins.
MfG
Falk
>Es sei denn, ich möchte in>einem best. Zeitintervall Interrupts haben, dann sollte die ISR>Abarbeitung nicht länger als das Zeitintervall dauern.
Die Bearbeitungsdauer einer ISR sollte immer kürzer sein, als deren
Aufruf. Sonst kommt das System ja nicht mehr hinterher...
>die ISRs nicht reentrant sind
meinst Du dieselbe ISR oder eine andere?
Dieselbe ISR nocheinmal aufzurufen, während sie selbst noch bearbeitet
wird, kann nie gut gehen. Eine andere ISR kann man mal
dazwischenschieben. Dann muss man aber ganz genau wissen, was man tut!
>>ISRs benötige, aber es soll ja auch nicht nur beim toggeln bleiben :-)>Dann nimm eine Quarz am Oszillator.
Nicht unbedingt. Wenn man z.B. im Batteriebetrieb stromsparend arbeiten
will, ist ein 32,768kHz Uhrenquarz die erste Wahl, da dieser im Sleep
Modus weiterlaufen kann und dabei grad mal ~1µA zieht. Der interne DCO
kann sehr einfach auf die Uhrenquarzfrequenz synchronisiert werden, was
ein präzises Timing ermöglicht!
>0000ffe0 <_vectors_end-0x20>:>...>ffec: 84 40 interrupt service routine at 0x4084>...>So ist es doch richtig, oder?Wenn an Adresse 0x4084 Deine ISR für den CCR0-IRQ anfängt... Ja!
Schau in Deiner main.lst nach, ob die ISR-Adresse stimmt.
Aber ich glaube schon, dass es stimmt:
1
TIMERA0_ISR:BIS#0x01,R13;0xFFECTimerACC0
2
RETI
Die ISR belegt 4Bytes an Code und der nächste Eintrag in der
Vector-Tabelle ist genau 4 Bytes später (0x4088)
>Der ACLK hat auf dem OSZI ca. 7µs high level und fast 10µs low level.>Das macht etwa 58,8kHz. Amplitude ist etwa 3,3V.
Nochmal: Gemessen an P5.6 (Pin50) oder an XOUT (Pin9)?
Sind auf dem Olimexboard eignetlich C4 und C5 bestückt?
Sollten sie nicht, da der MSP die Load-Kondensatoren für Uhrenquarz
schon integriert hat.
Zum CLK-Problem muss ich erstmal weiter nachdenken... ;-)
Also ich hab's grad mal ausprobiert...
Hab zwar 'nen F1232 und die IAR-Entwicklungsumgebung, aber vom Prinzip
her hab ich Deine Initialisierung für die Basic Clocks sowie für den
Timer_A hergenommen und alles hat auf Anhieb funktioniert!
Die Software an sich scheint also in Ordnung zu sein.
Ich vermute eher ein Hardwareproblem bei Deinem Quarz, MSP, Board, ...?
Oder dass eben doch was nicht mit den IRQ-Vektoren stimmt.
Versuch mal beim Debuggen nur einen Breakpoint in der ISR zu setzen und
im Continuous-Mode laufen zu lassen, ob er wirklich in der ISR ankommt
und was er dort dann macht.
>ist kurz danach der MCLK aus
Da der MCLK vom internen DCO getaktet wird und die Ausgabe an P5.4 ein
HW-Feature ist, scheint sich der µC irgendwie ganz dramatisch zu
verabschieden oder in einem Endlos-Reset zu hängen...???!!!
Hallo,
@ Falk: Ja, ich bin sehr bemüht ordentlich zu programmieren :-) Ich
hatte mir auch zwei Bücher über den MSP430 ausgeliehen, eins von Luecke
und das andere von Nagy.
Eigentlich stelle ich nicht viel an den Oszillatoreinstellungen rum.
Das OSCOFF bit im SR ist bei mir nicht gesetzt (Default), da ich den
MCLK vom DCO speise. Im Manual steht folgendes zum OSCOFF:
---------------------------------------------------------------------
OSCOFF Oscillator Off. This bit, when set, turns off the LFXT1 crystal
oscillator, when LFXT1CLK is not use for MCLK or SMCLK
---------------------------------------------------------------------
Muss ich das OSCOFF dann setzen, wenn ich den LFXT1 nicht für MCLK und
SMCLK sondern nur für ACLK brauche?
@ Stefan: > Die Bearbeitungsdauer einer ISR sollte immer kürzer sein,
als deren Aufruf. Sonst kommt das System ja nicht mehr hinterher...
Da bin ich ganz Deiner Meinung.
> Wenn an Adresse 0x4084 Deine ISR für den CCR0-IRQ anfängt... Ja!> Schau in Deiner main.lst nach, ob die ISR-Adresse stimmt.> Aber ich glaube schon, dass es stimmt:
Ich habe die main.lst gerade nicht da, aber ich habe früher dort schon
nachgesehen, die Adressen an denen die ISRs im Speicher beginnen stimmen
nach dem compilieren mit den von mir in der section vectors
eingetragenen Interruptvektoren überein. Wenn ich im debugger den PC mit
set $pc=0xFFEC auf 0xFFEC stelle, müsste er dann nicht im nächsten
Schritt in die entsprechende ISR springen?
>>Der ACLK hat auf dem OSZI ca. 7µs high level und fast 10µs low level.Das macht
etwa 58,8kHz. Amplitude ist etwa 3,3V.
>Nochmal: Gemessen an P5.6 (Pin50) oder an XOUT (Pin9)?
Das habe ich am P5.6 gemessen! Am Pin9 ist kein CLK-Signal. Bin mir bei
letzterem nicht mehr ganz sicher, werde ich heute Abend nochmal
überprüfen! Das wäre schon komisch oder?
Auf dem Olimexboard sind C4 und C5 mit jeweils 10pF bestückt! Vielleicht
baue ich die mal aus. Ich kann mir aber nicht vorstellen, das Olimex die
bestückt hat, ohne dass sie einen Sinn haben. Oder?
Stephan
>Muss ich das OSCOFF dann setzen, wenn ich den LFXT1 nicht für MCLK und>SMCLK sondern nur für ACLK brauche?NEIN
Mit OSCOFF schaltest Du LFXT1 ab und damit würdest Du ACLK auch
abschalten!
Der obige Satz besagt lediglich, dass OSCOFF nur dann gesetzt werden
kann, wenn LFXT1 nicht für MCLK oder SMCLK benutzt wird. Sozusagen
ein Sicherheitsfeature gegen versehentliches Ausschalten des Mainclocks
>Wenn ich im debugger den PC mit>set $pc=0xFFEC auf 0xFFEC stelle, müsste er dann nicht im nächsten>Schritt in die entsprechende ISR springen?
Ähhh..... nee!
In 0xFFEC steht ja kein Code oder Sprungbefehl sondern nur eine Adresse,
zu der gesprungen werden soll.
Also set $pc=0x4084 erscheint mir erfolgversprechender
@ Stephan (Gast)
>eingetragenen Interruptvektoren überein. Wenn ich im debugger den PC mit>set $pc=0xFFEC auf 0xFFEC stelle, müsste er dann nicht im nächsten>Schritt in die entsprechende ISR springen?
NEIN! Der MSP hat keine Interrupttabelle wie der AVR! Dort stehen nur
Adressen, KEIN Sprungbefehle in die ISR. Also ist ein Sprung IN die
Interruptvektoren total falsch!
>Auf dem Olimexboard sind C4 und C5 mit jeweils 10pF bestückt! Vielleicht>baue ich die mal aus. Ich kann mir aber nicht vorstellen, das Olimex die>bestückt hat, ohne dass sie einen Sinn haben. Oder?
Die sind nur sinnvoll, wenn man einen normalen Quarz mit 1..8 MHz
benutzt.
MfG
Falk
Hallo,
@ Falk, Stefan
>>Wenn ich im debugger den PC mit>>set $pc=0xFFEC auf 0xFFEC stelle, müsste er dann nicht im nächsten>>Schritt in die entsprechende ISR springen?>Ähhh..... nee!>In 0xFFEC steht ja kein Code oder Sprungbefehl sondern nur eine Adresse,>zu der gesprungen werden soll.>Also set $pc=0x4084 erscheint mir erfolgversprechender
OK, natürlich, ihr habt recht! Dort stehen keine JMPs o.ä. sondern nur
Sprungadressen! Aaaarggh!
Kann der TimerA CCIFG0-Interrupt ausgelöst werden, indem im TACCTL0
Register das bit 0 (CCIFG) manuell gesetzt wird? Falls ja, könnte so
getestet werden, ob die ISR richtig angesprungen wird?
Muss im TACTL Register das bit 1 TAIE gesetzt werden, damit der
CCIFG0-Interrupt beachtet wird?
@ Stefan: Danke, dass Du meine Setup Routine getestet hast.
Ich vermute auch, dass etwas mit der Hardware nicht stimmt.
Aber wenn, dann nur, weil es nicht richtig konfiguriert ist.
Ich habe das uart_test Beispiel (siehe Link zu den mspgcc-Beispielen
weiter oben im Posting) mit dem mspgcc compiliert. Das klappt
einwandfrei. Dort wird über RS232 ein Zeichen (vom Hyperterminal)
empfangen und mit einem Bytecount zurückgesendet.
Ich werde das Programm mal laden und die Signale ausmessen.
Liegt der 32kHz CLK auch am Pin 9 XOUT?
@ Falk:
> Die sind nur sinnvoll, wenn man einen normalen Quarz mit 1..8 MHz
benutzt.
Stören die, wenn der 32kHz Uhrenquartz statt einem 1..8 MHz Quartz
verwendet
wird?
Stephan
>Kann der TimerA CCIFG0-Interrupt ausgelöst werden, indem im TACCTL0>Register das bit 0 (CCIFG) manuell gesetzt wird?
Laut User-Guide ja!
>Falls ja, könnte so getestet werden, ob die ISR richtig angesprungen wird?
s. o.
>Muss im TACTL Register das bit 1 TAIE gesetzt werden, damit der>CCIFG0-Interrupt beachtet wird?Nein, TAIE ist der Timer-Overflow-IRQ!
>Liegt der 32kHz CLK auch am Pin 9 XOUT?
Mit Sicherheit. Das ist ja der Quarz angeschlossen (und an XIN)
>Stören die, wenn der 32kHz Uhrenquartz statt einem 1..8 MHz Quartz>verwendet wird?
Wenn Dein "uart_test" Beispiel mit dem Uhrenquarz funktioniert, dann
wohl nicht. Aber eigentlich sind sie unnötig, da ja 2x 6pF bereits im
MSP drin sind. Ich würde sie für den Uhrenquarzbetrieb auslöten!
Guten Abend,
Es ist kaum zu fassen, aber ich kann an keinem der beiden Pins XIN, XOUT
ein CLK signal messen. Ich habe über beiden Pins gemessen und von jedem
Pin zu GND. Ich habe in meiner SETUP Routine den ACLK ungeteilt auf den
Pin P5,6 ausgegeben, dort messe ich einen Clock, der aber mit ca.
17-20µs zu schnell ist. Was kann denn das bloss sein?
Stephan
@ Stephan (Gast)
>Es ist kaum zu fassen, aber ich kann an keinem der beiden Pins XIN, XOUT>ein CLK signal messen. Ich habe über beiden Pins gemessen und von jedem
Wie misst du denn? Hoffentlich mit einem 10:1 Tastkopf. Und selbst das
könnte unter Umständen den Oszillator abwürgen. Und vor allem wie misst
du ÜBER den PINs? Hoffentlich nicht mit der Masse vom Oszi an einem Pin.
>Pin zu GND. Ich habe in meiner SETUP Routine den ACLK ungeteilt auf den>Pin P5,6 ausgegeben, dort messe ich einen Clock, der aber mit ca.>17-20µs zu schnell ist. Was kann denn das bloss sein?
Es liegt was im Argen. 32kHz sind ~33us Periodendauer. Und das so
ziemlich genau.
MfG
Falk
Guten Tag!
Nachdem ich auf dem Olimex-Board MSP430-P1611 die Kondensatoren C4 und
C5 am 32kHz Quartz ausgelötet habe, hat der ACLK an P5.6 eine
Periodendauer von ca. 30µs. Am XOUT messe ich trotzdem kein Signal, ich
vermute es liegt an meinem Messequipment.
Zu den Interrupt Routinen hatte ich mit mit
msp430-objdump -DS main > asm.lst
das assembler listing ausgeben lassen. Am Ende des Listings finde ich
folgendes:
------------------------------------------------------------------------
---
Disassembly of section .vectors:
0000ffe0 <_vectors_end-0x20>:
ffe0: 5a 40 interrupt service routine at 0x405a
ffe2: 60 40 interrupt service routine at 0x4060
ffe4: 66 40 interrupt service routine at 0x4066
ffe6: 6c 40 interrupt service routine at 0x406c
ffe8: 72 40 interrupt service routine at 0x4072
ffea: 78 40 interrupt service routine at 0x4078
ffec: 7e 40 interrupt service routine at 0x407e
ffee: 82 40 interrupt service routine at 0x4082
fff0: 88 40 interrupt service routine at 0x4088
fff2: 8e 40 interrupt service routine at 0x408e
fff4: 94 40 interrupt service routine at 0x4094
fff6: 9a 40 interrupt service routine at 0x409a
fff8: a0 40 interrupt service routine at 0x40a0
fffa: a4 40 interrupt service routine at 0x40a4
fffc: 00 40 interrupt service routine at 0x4000
fffe: 00 40 interrupt service routine at 0x4000
------------------------------------------------------------------------
---
So ähnlich hatte ich das schon einmal gepostet. Beim RESET und dem
RST/NMI Interrupt wird zur Adresse 0x4000 gesprungen, die anderen ISR
sind an den entsprechenden Adressen definiert.
Nächster Schritt:
LPT1 freigeben:
modprobe ppdev
chmod 666 /dev/parport0
gdb-proxy starten:
msp430-gdbproxy --port=2000 msp430
ddd Debugger starten:
ddd --debugger msp430-gdbproxy
Im ddd mit dem Button "connect" debugger und CPU verbinden.
Programm flashen mit
load main
symbol-file main
PC steht dann auf 0x4000, SP ist auf 0x3900 initialisiert.
Dann mit
disassemble 0xffe0 0xffff
den Speicherbereich des MSP430F1611 angezeigt, an dem die Sprungadressen
zu den ISRs sind. Das hoffe ich zumindest :-). Folgendes Resultat:
(gdb) disassemble 0xffe0 0xffff
Dump of assembler code from 0xffe0 to 0xffff:
0x0000ffe0: interrupt service routine at 0xffff
0x0000ffe2: interrupt service routine at 0xffff
0x0000ffe4: interrupt service routine at 0xffff
0x0000ffe6: interrupt service routine at 0xffff
0x0000ffe8: interrupt service routine at 0xffff
0x0000ffea: interrupt service routine at 0xffff
0x0000ffec: interrupt service routine at 0xffff
0x0000ffee: interrupt service routine at 0xffff
0x0000fff0: interrupt service routine at 0xffff
0x0000fff2: interrupt service routine at 0xffff
0x0000fff4: interrupt service routine at 0xffff
0x0000fff6: interrupt service routine at 0xffff
0x0000fff8: interrupt service routine at 0xffff
0x0000fffa: interrupt service routine at 0xffff
0x0000fffc: interrupt service routine at 0xffff
0x0000fffe: interrupt service routine at 0xffff
End of assembler dump.
(gdb)
Deswegen kommt die CPU nach einem RESET nicht in die Pötte, weil sofort
nach einem RESET an 0xffff gesprungen wird, oder verstehe ich das wieder
falsch? Woran könnte das liegen?
Stephan
Hurra!
Jetzt geht es, ich habe nach dem laden des Programms in die CPU mit dem
debugger die Speicheradressen nachträglich geändert und zwar
folgendermassen:
(gdb) set *0xfffe = 0x4000
(gdb) set *0xfffc = 0x4000
(gdb) set *0xffec = 0x4084
(gdb) disassemble 0xffe0 0xffff
Dump of assembler code from 0xffe0 to 0xffff:
0x0000ffe0: interrupt service routine at 0xffff
0x0000ffe2: interrupt service routine at 0xffff
0x0000ffe4: interrupt service routine at 0xffff
0x0000ffe6: interrupt service routine at 0xffff
0x0000ffe8: interrupt service routine at 0xffff
0x0000ffea: interrupt service routine at 0xffff
0x0000ffec: interrupt service routine at 0x4084
0x0000ffee: interrupt service routine at 0xffff
0x0000fff0: interrupt service routine at 0xffff
0x0000fff2: interrupt service routine at 0xffff
0x0000fff4: interrupt service routine at 0xffff
0x0000fff6: interrupt service routine at 0xffff
0x0000fff8: interrupt service routine at 0xffff
0x0000fffa: interrupt service routine at 0xffff
0x0000fffc: interrupt service routine at 0x4000
0x0000fffe: interrupt service routine at 0x4000
End of assembler dump.
(gdb) c
Continuing.
Jetzt geht es! Nun muss ich herausfinden, warum in meinem object file
die Interruptvektortabelle richtig ist, aber nicht richtig in die CPU
geladen wird. Habt ihr vielleicht schon eine Idee?
Gruß Stephan
>Hurra!
Na also :-)
>Nachdem ich auf dem Olimex-Board MSP430-P1611 die Kondensatoren C4 und>C5 am 32kHz Quartz ausgelötet habe
Ich weiß nicht, was Olimex sich da gedacht hat, C4 und C5 zu bestücken?
Die sind eigentlich nur dann vorzusehen, falls man anstelle von Q1
(32kHZ) den Q2 (HF-Quarz) bestückt!
1
>Disassemblyofsection.vectors:
2
>0000ffe0<_vectors_end-0x20>:
3
>...
4
>ffec:7e40interruptserviceroutineat0x407e
Wieso auf einmal 0x407E und nicht 0x4084 ?
1
>(gdb)disassemble0xffe00xffff
2
>Dumpofassemblercodefrom0xffe0to0xffff:
3
>0x0000ffe0:interruptserviceroutineat0xffff
4
...
>Deswegen kommt die CPU nach einem RESET nicht in die Pötte, weil sofort>nach einem RESET an 0xffff gesprungen wird, oder verstehe ich das wieder>falsch? Woran könnte das liegen?
Das kann jetzt auch nicht sein, denn wenn der µC direkt nach dem Reset
nach 0xFFFF hüpft, schmiert er ab oder macht 'nen Endlos-Reset.
Dann würde aber niemals Deine Init-Routine ausgeführt werden, die die
Clocks setzt und P5.4 und P5.6, wodurch Du ja ACLK und MCLK messen
kannst!
Vielleicht nimmt er tatsächlich die Adresse 0x407E anstelle von 0x4084
(s.oben) und hängt sich dann auf?
>Nun muss ich herausfinden, warum in meinem object file>die Interruptvektortabelle richtig ist, aber nicht richtig in die CPU>geladen wird. Habt ihr vielleicht schon eine Idee?
Nee, leider nicht!
Vielleicht im GCC-Forum mal die Spezialisten über Deine Tools ausfragen?
Warum benutzt Du nicht die freie IAR-Kickstart Entwicklungsumgebung?
C-Code Beschränkung 2 oder 4k, Assembler unbegrenzt.
Habe damit bislang persönlich sehr gute Erfahrungen gemacht!
>>Deswegen kommt die CPU nach einem RESET nicht in die Pötte, weil sofort>>nach einem RESET an 0xffff gesprungen wird, oder verstehe ich das wieder>>falsch? Woran könnte das liegen?>Das kann jetzt auch nicht sein, denn wenn der µC direkt nach dem Reset>nach 0xFFFF hüpft, schmiert er ab oder macht 'nen Endlos-Reset.>Dann würde aber niemals Deine Init-Routine ausgeführt werden, die die>Clocks setzt und P5.4 und P5.6, wodurch Du ja ACLK und MCLK messen>kannst!>Vielleicht nimmt er tatsächlich die Adresse 0x407E anstelle von 0x4084>(s.oben) und hängt sich dann auf?
Der µC ist auch sofort abgestürzt und nicht in die Setup-Routine
gegangen etc., wenn ich ihn ohne debugger geflasht und gestartet habe
mit
msp430-jtag -e main
von der Commandozeile.
Das steppen ging nur im debugger. Nach dem Verbinden des debuggers mit
der CPU (Button Connect) stand der PC immer auf 0xffff. Den habe ich
dann mit
set $pc=0x4000
auf die Setup-Routine gesetzt und konnte anschließend steppen. Beim
schrittweisen steppen sind nie Interrupts aufgetreten, warum weiß ich
auch nicht. Sobald ich aber den µC mit dem Befehl continue "von der
Leine" gelassen habe ist er abgeschmiert. Dann war nach kurzer Zeit der
MCLK weg, wie gesagt.
Jetzt wo ich die ISR-Sprungvektoren manuell geändert habe, steht der µC
nach dem Connect im Debugger sofort auf 0x4000! Wenn ich jetzt steppe,
treten immer noch keine Interrupts auf. Er läuft jetzt aber im Continue,
un auch, wenn ich den JTAG stecker vom board ziehe!
Bezüglich 0x407e und 0x4084: Da habe ich wahrscheinlich das assembler
listing von meinem Programm erwischt, bei dem ich einige Zeilen in
Mainloop auskommentiert habe. Ich habe die Zeilen wieder einkommentiert
und überprüft. An Adresse 0xffec steht die Sprungadresse 0x4084, die ISR
für den TIMERA Interrupt befindet sich an 0x4084. Habe ich beides mit
disassemble überprüft, und nicht etwa im object file ;-)))
>Warum benutzt Du nicht die freie IAR-Kickstart Entwicklungsumgebung?>C-Code Beschränkung 2 oder 4k, Assembler unbegrenzt.
Die läuft nur unter Windows, oder? Ich hatte mir vorgenommen, unter
Linux zu entwickeln. Sicher würde mir die IAR IDE so manchen Albtraum
wie den letzten ersparen. Mal sehen!
Linux oder Windows, hin oder her, beides hat Vor und Nachteile... bevor
an dieser Stelle große Diskussionen über das richtige Betriebssystem
losbrechen :-) möchte ich Euch für Eure tatkräftige Unterstützung
danken. Ihr habt mir sehr weitergeholfen!
Ich werde mich mal an das gcc Forum wenden, was evtl. mit dem debugger
oder meinen object files nicht stimmt.
Wie gesagt, es wird nicht beim Toggeln der LED bleiben.... :-)
Also bis bald!
Gruß Stephan