Hallo Community,
ich arbeite das erste Mal seit Langem wieder mit MSP430ern. Ich habe ein
Launchpad Development Board mit einem MSP430FR4133 an Bord.
Ich möchte den Mikrocontroller zunächst mit der höchstmöglichen
Taktfrequenz betreiben, also 16 MHz. Das sollte gemäss dem Datenblatt
mit dem DCO mit FLL und interner Referenz möglich sein.
Leider schaffe ich es nicht, irgendeine beliebige Clock-Konfiguration zu
verifizieren, ich messe immer etwas anderes als erwartet. Beispielsweise
sollte meinem Verständis nach FLLN = 255 und FLLD = 0 gemäss der Formel
aus dem MSP430FR4xx User Guide, Kapitel 3.2.5 zu einem MCLK von 8.389
MHz führen.
Ich toggle einen Pin (ohne Loop, da ich nur einzelne MOV instructions
möchte) und messe nach mit einem Logic Analyzer: 1.572 MHz.
Was stimmt da nicht?
Das analoge Signal sieht unschön aus, ist aber auch nur mit 50 MS/s
aufgenommen. Das digitale hingegen mit 500 MS/s. Die Messung ist gleich,
wenn ich das Board galvanisch getrennt speise.
Ebenfalls merkwürdig ist, dass die 6 Takte in einem Loop-Durchgang schon
zeitlich variieren. Ich messe (jeweils zwischen zwei Flanken): 634 ns,
634 ns, 714 ns, 636 ns, 636 ns, 634 ns, 634 ns, 714 ns, 636, 636 ns.
Der Code:
1
intmain(void){
2
P2DIR=0x20;//set P2.5 as output
3
PM5CTL0&=~LOCKLPM5;//disables default high-Z mode of GPIO
4
WDTCTL=WDTPW|WDTHOLD;//disable_watchdog
5
6
CSCTL3=SELREF0;//use REFOCLK as reference for FLL, FLLREFDIV=1
7
CSCTL2=0x00ff;//FLLN=255, FLLD=0
8
CSCTL1=(CSCTL1&~0x0f)|0x0A;//DCO range 16 MHz, Modulation on, no trim
Ehm du must den DCO noch Zuweisen.
und den Resistor richtig setzen.
usw,
Der MSP430FR4133 dazu sogar extra Default Settings im Flash(Siehe Bild)
Deine Routine (Toggle) macht unterschiedliche Zeiten, nach jedem 6ten
Clock
da ein Rücksprung passiert.
Du kannst ja den DCO direkt auf ein Pin Legen zum messen, dazu gibt es
extra Appnotes von TI
Etwas mehr Angaben wären Hilfreich.
Es gibt übrigens ein Tool von TI womit man den DCO setzen kann.
Einiges findest du unter:
https://www.ti.com/lit/an/slaae38/slaae38.pdf?ts=1652832485339
Und es gibt für 16MHz auch Fertige Konfigurationen von TI Downloadbar.
Da der Chip mehrere Ozilatoren und Clock onboard hat musst du den
richtigen noch der CPU Zuweisen(SMCLK,MCLK, usw)
fragjanur schrieb:> rein interessehalber : Welchen Compiler verwendest Du und wie lädst Du> den Code in den Controller ?
Ich verwende den GNU GCC Compiler, msp430-elf-gcc 12.1.0.
Zum Konvertieren von ELF zum Intel-Hex-Format dann msp430-elf-objcopy
und schlussendlich den MSP Flasher v1.3.20 von TI, um das Hex-File in
den Controller zu laden.
Ich konnte mit diesem Setup erfolgreich die "Out-of-the-Box"-Demo
kompilieren und testen.
Bei Interesse kann ich auch mein Makefile mit den detailierten Befehlen
teilen.
Hast du den GCC Aktiv während du misst?
Der kann dir nämlich dazwischen Funken und dein Programm per Interrupt
unterbrechen.
Das würde zu deinem Fehlerbild passen:
Tim Fuchser schrieb:> Ebenfalls merkwürdig ist, dass die 6 Takte in einem Loop-Durchgang schon> zeitlich variieren.
Hilfreich wäre wenn du das Assembler Listing welches der C-Kompiler
macht posten würdest dort würde man sehen, was der Kompiler tatsächlich
aus deinem Programm gemacht hat.
(ev Optimiert er dein Programm ja, je nach Einstellung)
Gruß
Vielen Dank für die Antwort.
Patrick L. schrieb:> Ehm du must den DCO noch Zuweisen.> und den Resistor richtig setzen.> usw,
Was meinst du genau mit Zuweisen? Dein Screenshot zeigt die
Kalibrierungswerte für den DCO, die meiner Meinung nach POR verwendet
werden sollten. Das DCOFTRIM-Bit im Register CSCTL1 ist per default 0,
also "[...] DSO applies default settings from manufacture."
Patrick L. schrieb:> Deine Routine (Toggle) macht unterschiedliche Zeiten, nach jedem 6ten> Clock> da ein Rücksprung passiert.
Der Sprung nach 6 Zyklen macht Sinn. Was ich mir nicht erklären kann
sind die unterschiedlichen Periodenlängen "innerhalb" der 6 Zyklen.
Patrick L. schrieb:> Es gibt übrigens ein Tool von TI womit man den DCO setzen kann.> Einiges findest du unter:> https://www.ti.com/lit/an/slaae38/slaae38.pdf?ts=1652832485339>> Und es gibt für 16MHz auch Fertige Konfigurationen von TI Downloadbar.
Vielen Dank für die Links. Werde ich mir anschauen.
Patrick L. schrieb:> Da der Chip mehrere Ozilatoren und Clock onboard hat musst du den> richtigen noch der CPU Zuweisen(SMCLK,MCLK, usw)
Auch das sollte schon richtig sein, oder? Nach POR is SELMS auf
DCOCLKDIV (in CSCTL4). Ich verstehe das so, dass für CPU + GPIO nur MCLK
wichtig ist, der damit richtig gesetzt sein sollte.
Patrick L. schrieb:> Hast du den GCC Aktiv während du misst?>> Der kann dir nämlich dazwischen Funken und dein Programm per Interrupt> unterbrechen.>> Das würde zu deinem Fehlerbild passen:>> Tim Fuchser schrieb:>> Ebenfalls merkwürdig ist, dass die 6 Takte in einem Loop-Durchgang schon>> zeitlich variieren.
Nein. Das Flashtool meldet "Disconnecting from device...done". Einen
Debugger (auf dem PC) habe ich nicht aktiv. Könnte aber schon sein, dass
der andere Mikrocontroller (Debugger/USB-Brücke) auf dem Dev-Board dem
MSP430 irgendwie reinfunkt. Ich glaube da sind Jumper auf dem Board, um
die zu trennen. Das werde ich morgen mal testen.
Patrick L. schrieb:> Hilfreich wäre wenn du das Assembler Listing welches der C-Kompiler> macht posten würdest dort würde man sehen, was der Kompiler tatsächlich> aus deinem Programm gemacht hat.> (ev Optimiert er dein Programm ja, je nach Einstellung)
Das habe ich geprüft. Sieht meiner Meinung nach gut aus:
Nach dem POR sitzt die CPU auf dem LO und nicht auf dem DCO.
Das ist bei fast allem MSP430 so.
Müsste jetzt aber selber mal im DB nachschauen, und das ist mit dem
Handy (Bin Unterwegs) etwas schwierig.
Aber ich kann wenn ich morgen wieder im Büro bin mal nachschauen.
Aber wie gesagt Default ist normalerweise der Clock der CPU auf dem LO
Oszilator.
Auch wenn der DCO in den Fehlerinterrupt wegen falschem Setting läuft,
(Etwa 16MHz gesetzt aber nicht genügend Spannung auf der CPU), geht die
CPU auf den LO zurück.
16MHz macht die CPU erst ab ca. 3.3V
Wenn dein Launchpad den ENERGIA mit drauf hat kannst du übrigens die
Betriebsspannung des MSP430 setzen!
Welches Launchpad hast du?
PS: habe jetzt grad gelesen das die 1.xx MHz die Default Frequenz ist
sieht nach Falsche, DCO und/oder FLL setting aus!
Danke für die Hilfe. Ich habe es nun mit dem Codebeispiel von TI
hingekriegt (msp430fr413x_CS_03.c).
Der Hauptfehler war wohl die Messung per Pin-Toggle, statt den MCLK
direkt auf einen Pin zu legen. Im Screenshot sieht man den Unterschied.
In der CPU wird schon eine Instruction pro Taktflanke ausgeführt, oder?
Liegt das Problem daran, dass die GPIO-Peripherie nicht schnell genug
ist?
Habe in Erinnerung dass das bei AVR oder PIC nie ein Problem war.
1
intmain(void){
2
P1DIR=(1<<4);//set P1.4 as output
3
P2DIR=(1<<5);//set P2.5 as output
4
PM5CTL0&=~LOCKLPM5;//disables default high-Z mode of GPIO
5
WDTCTL=WDTPW|WDTHOLD;//disable_watchdog
6
7
FRCTL0=FRCTLPW|NWAITS_1;
8
CSCTL0=0;
9
CSCTL3|=SELREF__REFOCLK;//use REFOCLK as reference for FLL, FLLREFDIV=1
Tim Fuchser schrieb:> In der CPU wird schon eine Instruction pro Taktflanke ausgeführt, oder?
Ja, wenn es ein NOP ist. Ansonsten siehe Abschnit 4.5.1.5 des User's
Guide.
Tim Fuchser schrieb:> Danke für die Hilfe. Ich habe es nun mit dem Codebeispiel von TI> hingekriegt (msp430fr413x_CS_03.c).
Gerne :-)
> Der Hauptfehler war wohl die Messung per Pin-Toggle, statt den MCLK> direkt auf einen Pin zu legen. Im Screenshot sieht man den Unterschied.
Das kann Tatsächlich zu Problemen Führen, weshalb ich dir dies auch
Empfohlen hab.
> In der CPU wird schon eine Instruction pro Taktflanke ausgeführt, oder?
Kommt auf die Instrucktionen an. bei Imediate Adressing ja
Als Beispiel:
> P2OUT = 0x20;
kann entweder vom Kompiler als Direkt adressing oder aber auch als
Indirekt adressing oder sogar als Indexet usw kompiliert werden (Je nach
Einstellung) so kann der selbe "C"- befehl entweder in 2 oder eben auch
in 6 Cyclen ausgeführt werden. Aber auch hier gilt, wenn dumm gelaufen,
kann es auch 4 x mehr sein (Also 24 Cycles)
Dies trifft dann aber in der FLAHS Version zu.
Da wenn es Zeitkritisch ist muss man beim Kompiler echt auf die
eingestellten Parameter achten.
Es gilt grad speziell in den Extended Befehlen (werden leider aber nicht
alle vom GCC-C-Kompiler unterstützt)
Es gibt da durchaus auch Befehle die mal bis zu 64 Taktcyclen brauchen
können (ja wissen viele nicht)
Etwa der [POPM-A] wenn alle Register vom STACK geholt werden und der
Stack auf das FRAM oder gar FLASH zeigt.
(Ja das kann man Missbrauchen , um alle Register auf einmal mit
Festwerten zu Laden).
Dann kann die CPU tatsächlich im Dümmsten Fall 64 Taktcyclen Brauchen !
Es gibt noch andere Kniffels mit den Extendet Befehlen die aber nur
die XV2 CPU unterstützt, die im MSP430FR4133 nicht verbaut ist.
> Liegt das Problem daran, dass die GPIO-Peripherie nicht schnell genug> ist?
Nein, das hat eine Andere Ursache.
Bei 16MHz muss die CPU mit dem Cache arbeiten, da das FRAM Maximal 8MHz
ohne zu Cachen verarbeiten kann. Die Peripherie wäre eigentlich schnell
genug.
Aber wie schon oben geschrieben:
> P2OUT = 0x20;
als Beispiel 1,5xx MHz mit 16MHz MCLOK durchaus ein Resultat aus 10
Taktcycen besteht der Befehl jeweils 4 Cycles x 2 (jeweils ein
WaitState) + 2 Cycles für in die Pheripherie zum übertragen.
Zeitkritisches Programmieren ist eine Herausforderung und nicht nur bei
den MSP430, ich kenne da auch Situationen aus ARM, PENTIUM, ATOM usw µC
die bei I/O Befehlen mit 100 Cyclen zu buche schlagen.... (Ist aber
natürlich Worst Case)
> Habe in Erinnerung dass das bei AVR oder PIC nie ein Problem war.
Ist beim MSP430FRxxx auch so, anders bei der MSP430Lxxxx oder
MSP430Cxxxx oder MSP430Pxxxx Version, den diese sind auf Hyper-Lowpower
ausgelegt, oder halt OTP usw, und wirklich keine Anfänger-µC's
Aber auch hier gilt, Kommt ganz auf die Programmierung und grad bei den
MSP430 I/O's, halt auch auf die Beschaffenheit an. es gibt I/O's die im
speziellen LPM Mode dann auch eine "Bremse" haben, sprich WaitStates
auslösen. Aber halt auch wieder Sonderfälle.
> https://www.ti.com/tool/MSP-EXP430FR4133
Da gibt es auch noch Sonderfälle, es kann ganz dumm laufen, das dir der
Debugger noch eine Bremse reinhaut, nämlich dann wenn er nach jeder
Instruktion Register usw ausliest, oder ev auch im Energy Trace Mode
ist.
Das EEM (ExtendetEmulationModul) kann ebenfalls Zeit in Anspruch nehmen.
Ist dann halt auch wieder alles Parameter, Setting usw. abhängig.
So wohl im Debugger als auch in der IDE, oder nicht zuletzt auch wenn in
der CPU Situationen vorkommen, die sie Ausbremst, können auch Interrupts
usw sein.(Siehe unter Virtual- oder Software- Breakpoints)
Ich arbeite nicht mit dem GCC, sondern vorwiegend mit dem IAR. deshalb
kann ich dir da nicht mit Sicherheit sagen, was der GCC im µC alles
setzt.
Aber aus der Erfahrung vom IAR, ist es ein großer Unterschied ob ich es
im DEBBUG, oder LIBRARY, oder im EXECUTABLE-Mode kompiliere.
PS: Diese Angaben ohne Gewähr, habe mit dem Handy an Geslossener
Barriere schnell geantwortet, keine Zeit zur Verifykation ...LOL
@[Tim Fuchser]
Kleines Experiment für dich:
Schreib das Programm so um dass es vom FRAM ins RAM Kopiert wird.
und führe es dan im RAM aus und vergleiche was heraus kommt. :-)
Kleiner Tipp:
RAM unterstützt 16MHz FRAM nur 8MHz!
Ganz extrem wird es wenn du einen 25MHz MSP430 mit Flash ferwendest, und
das selbe Experiment machst. das können dann regelrecht "Welten" sein
;-)
Vor allem dann wen das Programm zu groß für das Cache, des MSP430 wird
:-)
73 55
Danke für die ausführliche Antwort, echt spannend!
Patrick L. schrieb:> Kleiner Tipp:> RAM unterstützt 16MHz FRAM nur 8MHz!
Ich rufe nun in meinem C-Programm folgenden Assembly-Code auf:
1
.section .data
2
.global blink
3
4
blink:
5
mov.b #0x20, &0x0203
6
mov.b #0x00, &0x0203
7
mov.b #0x20, &0x0203
8
mov.b #0x00, &0x0203
9
mov.b #0x20, &0x0203
10
mov.b #0x00, &0x0203
11
mov.b #0x20, &0x0203
12
mov.b #0x00, &0x0203
13
mov.b #0x20, &0x0203
14
mov.b #0x00, &0x0203
15
jmp blink
Das toggelt wie vorhin P2.5. Das Disassembly davon sieht dann so aus:
1
00002012 <blink>:
2
2012: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020
3
2016: 03 02
4
2018: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
5
201c: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020
6
2020: 03 02
7
2022: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
8
2026: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020
9
202a: 03 02
10
202c: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
11
2030: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020
12
2034: 03 02
13
2036: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
14
203a: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020
15
203e: 03 02
16
2040: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
17
2044: e6 3f jmp $-50 ;abs 0x2012
Man beachte den Offset von 0x2012, der jetzt im RAM liegen sollte
(0x2000-0x27FF).
In der Messung sieht man jetzt schön, wie die Unregelmässigkeiten weg
sind. Bestätigt also, dass das FRAM-Caching die Ursache dafür gewesen
sein müsste.
Die Laufzeiten lassen sich jetzt abzählen: 3 Cycles high, 4 Cycles low,
6 für den jmp. Ich verstehe leider noch nicht ganz, wie diese zustande
kommen, vorallem wieso das Setzen auf Null länger dauert.
Clemens L. schrieb:> Ansonsten siehe Abschnit 4.5.1.5 des User's> Guide.
Es handelt sich bei den MOV um "Format I (Double-Operand)" Instructions.
Wie erkenne ich welcher "Address mode" verwendet wird, sodass ich die
Anzahl Zyklen aus Tabelle 4-10 lesen kann?
msp430-elf-objdump hat beim Disassembly "r3 As==00" hingeschrieben, also
Source Addressing Mode ist "Register Mode". Mit &EDE als "Destination
Addressing Mode" würden die 3 Zyklen stimmen. Aber wie kommen die 4 für
0x0020 zustande?
Auch beim Jump bin ich mir unsicher. Das Datenblatt sagt: "All jump
instructions require one code word and take two CPU cycles to execute,
regardless of whether the jump is taken or not."
Wieso messe ich 6 und nicht 2 Zyklen?
Also bim kurz Drüberschauen:
1.) Tim Fuchser schrieb:> Danke für die ausführliche Antwort, echt spannend!
Gerne :-)
2.)Tim Fuchser schrieb:> Die Laufzeiten lassen sich jetzt abzählen: 3 Cycles high, 4 Cycles low,> 6 für den jmp. Ich verstehe leider noch nicht ganz, wie diese zustande> kommen, vorallem wieso das Setzen auf Null länger dauert.
Nein, eigentlich ist korrekt:
> mov.b #0x00, &0x0203 ->= [clr.b &0x0203]
Braucht 3 Cycles
> mov.b #0x20, &0x0203
braucht 4 Cicles
Siehst du wen du das Listing ansiehst:
> 2018: c2 43 03 02 mov.b #0, &0x0203 ;r3 As==00
ist eigentlich ein Registred MOV oder auch Emulatet CLR Befehl,und
ist daher schneller
> 201c: f2 40 20 00 mov.b #32, &0x0203 ;#0x0020> 2020: 03 02
Ist der Tasächliche MOV Befehl
Daher rührt der Unterschied.
3.)Mann könnte das Ganze noch Optimieren wenn man z.B. P2.0 verwenden
würde,
und nicht unbedingt den [MOV.B #XX,&YYYY] verwendete
Vielen Dank, ich glaube ich habe es jetzt viel besser verstanden.
Ich hatte irgendwie die Vorstellung 1 Assembly-Instruction = 1 Takt zu
fest im Kopf und konnte deshalb auch das Listing nicht richtig lesen.
Wenn man das Listing richtig versteht und versteht wie das mit der
Intruktionslänge und dem PC läuft, stimmt auch alles mit dem User Guide
überein :)
Patrick L. schrieb:> Mann könnte das Ganze noch Optimieren wenn man z.B. P2.0 verwenden> würde
Das deshalb, weil dann auch der Constant Generator (also R3 mit As==01)
verwendet werden kann? -> Register MOV (3 Zyklen)
Tim Fuchser schrieb:> Das deshalb, weil dann auch der Constant Generator (also R3 mit As==01)> verwendet werden kann? -> Register MOV (3 Zyklen)
Richtig, du lernst schnell :-)
Und wenn man es noch schneller machen will, nimt man nicht den MOV
befehl, da man so beispielsweise mehr Programmstepps braucht.....
Kleine Denkaufgabe für dich:
1.)...Was wäre die Alternative zu 2 unterschiedlichen MOV befehlen?
2.)... kann ich den Befehl auch auf 2 Taktzyklen Verkürzen?
3.)... wäre es auch möglich Ohne den MCLK direkt auf einen Pin zu legen,
ein MCLK/2 auf ein Pin zu haben,
ohne dass die CPU keine Zeit mehr, für andere Aufgaben hat?.
73 55