Forum: Compiler & IDEs Low-Frequency-Clk MSP430


von Jan Stumpf (Gast)


Lesenswert?

Hi!

ich versuche z.Z. verzweifelt einen MSP430 mit einem 32khz Uhrenquarz
zum Laufen zu bewegen (MSP430F1121). Ich hab, wie im Datenbaltt
beschrieben nur den Quarz an XIN/XOUT angeschlossen und verwende
folgenden Init-Code :

void vClockInit( void ){
     WDTCTL = WDTPW + WDTHOLD;     /* Watchdog deaktivieren */
     BCSCTL1 &=  ~0x30;//select low-frequencymode, ACKL-Divider = 1
     BCSCTL2 = 0xC8;               /* set MCLK=ACLK*/
     }

kommt ursprünglich aus der c't. Laut Datenblatt ist beim LF-Mode ja
das abfragen des Errorbits nicht nötig, oder? Am Oszi bekomm ich zwar
ein 32 khz Signal, daß allerdings nur eine Amplitude von 360mV hat (um
2.5V herum, bei 3.6V VCC). Das ist doch nicht normal, oder? Hat jemand
vieleicht ein Codesample zur Initialisierung des Clks für den mspgcc
bei 32Khz? Oder hat jemand ne Idee, was ich falsch mache?

Vielen Dank am Voraus

Jan Stumpf

von Jörg Zastrau (Gast)


Lesenswert?

MSP430 LF-XTAL,

ich fange gerade mit dem MSP430 an und bin gestern gleich
bei der Programmierung der ersten paar Zeilen auf das gleiche
Problem gestossen.

Ich benötige den Watchdog ebenfalls im Interval-Mode, um den
DSO zu synchronisieren, da TimerA für komplett für andere Zwecke
benötigt wird.

MSP430F1232 läuft mit 3,4V, zweilagiger Platinenaufbau. Uhren-
quarz schwang nicht.

Erster Augenschein:
- Der super-duper Billigquarz tut nicht (möglicherweise auch
  zu lange gelötet) trotz passender Spezifikation.
- Anderer Quarz mit 2 * 3pF parallel tuts... den im Datenblatt
  empfohlenen 5,1MOhm-Widerstand habe ich mir verkniffen, da
  VDD>2,5V.
- Dummerweise habe ich mich verlayoutet und auf der Rückseite
  der XIN/XOUT-Pins sind ein Eingang und der korrespondierende
  Ausgang eines derzeit noch unbeschalteten OPs angeordnet (schwingt
  natürlich) Möglicherweise gibt es dort einen Einfluß.
  Das wurde im Layout jetzt berücksichtigt, so daß auch der
  gegenüberliegenden Seite beim nächsten Mal Masseflächen
  vorhanden sind, so wie es sein sollte.

Fazit: Aufpassen beim Layout, brav Ground-Traces legen und schön
       Abstand halten von anderen Leitungen.

Jetzt noch eine Beobachtung zum MSP-GCC und Watchdog (derzeit noch
XY-ungelöst):

- Der DSO schwingt sofort an, beim Umschalten des Watchdog auf
  LFOSC als Taktgeber muß erst eine Weile gewartet werden.
  Code-Snipped vom anderen Thread hier (TI-Code):

  do {
        IFG1 &= ~=OFIFG           // Clear OSC-Fault Flag
        for (i=0xff; i>0; i--);   // settle time
  } while (IFG1 & 0FIFG);         // OSC-Fault?

- GDB schmiert ab beim Verwendung von ACLK beim Watchdog, beim
  Verwendung des DSO klappt es -> möglicherweise läuft die LFCLK
  durch und erzeugt mehrere Interrupts während eines Steps, was
  den JTAG durcheinanderbringt oder GDB verwendet selbst diese
  Methode, um SW-Breakpoints zu setzten (weis jemand Rat?)
  Stand-alone funzt es aber.

- Man kann bei den meisten MSPs einen IO-Pin dazu verurteilen,
  die ACLK gebuffert auszugeben, bei mir wäre das glaube ich P2.0,
  wenn dort nicht was dranhängen würde.

zu Deinem Problem:

  Der Watchdog muss natürlich auch wieder eingeschaltet werden,
  sprich WDTHOLD darf beim nächsten Befehl nicht gesetzt sein.


73, Jörg

von Jörg Zastrau (Gast)


Lesenswert?

Self-Re

Du hast natürlich recht... Im LF-Mode scheint das Error-Flag
nicht gesetzt zu werden (slaa081.pdf)

Jörg

von Jan Stumpf (Gast)


Lesenswert?

Hi Jörg!

>Erster Augenschein:
>- Der super-duper Billigquarz tut nicht (möglicherweise auch
>  zu lange gelötet) trotz passender Spezifikation.
hmm, vieleicht ist meiner auch nicht gut genug. Ich hatte nur bisher
keine Probleme mit Quarzen.

>- Anderer Quarz mit 2 * 3pF parallel tuts... den im Datenblatt
>  empfohlenen 5,1MOhm-Widerstand habe ich mir verkniffen, da
>  VDD>2,5V.
das werde ich mal ausprobieren.

>- Dummerweise habe ich mich verlayoutet und auf der Rückseite
>  der XIN/XOUT-Pins sind ein Eingang und der korrespondierende
>  Ausgang eines derzeit noch unbeschalteten OPs angeordnet (schwingt
>  natürlich) Möglicherweise gibt es dort einen Einfluß.
>  Das wurde im Layout jetzt berücksichtigt, so daß auch der
>  gegenüberliegenden Seite beim nächsten Mal Masseflächen
>  vorhanden sind, so wie es sein sollte.
also wenn das mit 32khz nicht funktioniert, ist das doch schon ein
ziemlicher Nachteil des MSP430. ich achte bei meinen designs auch immer
auf EMV, aber sowas muss bei 32khz schon möglich sein.

>zu Deinem Problem:
> Der Watchdog muss natürlich auch wieder eingeschaltet werden,
> sprich WDTHOLD darf beim nächsten Befehl nicht gesetzt sein.
aha, da könnte mein fehler noch liegen.

Könntest du deinen Initcode mal posten? Wäre super!

danke

Jan

von Jörg Zastrau (Gast)


Angehängte Dateien:

Lesenswert?

Hi Jan,

die ersten Schritte mit dem MSP430 sind gemacht und das "Gerippe"
für meine Applikation steht.

Ich brauche eine relativ hohe quarzstabile Frequenz.
Der Timer A ist durch eine PWM komplett belegt, d.h.
ich muß auf den WDT-Timer im Intervall-Modus zurückgreifen.

Statt einer FLL habe ich jedoch in Anlehnung an SLAA074 eine
PLL gebastelt. Da diese bei mir alle 24kHz einrasten kann ist
zunächst eine schnelle Auswahl des benötigten Frequenzbereichs
nötig.

Das Programmlauf sieht derzeit wie folgt aus:

- Auf den LFXTCLK warten mittel TimerA, da kein OSC-Fault
  generiert wird. Dauert bei mir ca. 200ms! (Billigquarz)
- Der WDT wird nun mit ACLK gespeist mit einer Periode von
  ca. 15ms. Timer A zählt nun DCO-Zyklen.
- Die RSEl-Einstellungen werden (mit DCOCTL=0) so lange
  ausgehend vom Maximalwert verringert, bis eine zu geringe
  Frequenz ermittelt wird.
- Danach kann es nur noch aufwärts gehen und eine passende
  Einstellung von DCOx und MODx wird mit successiver
  Approximation wiederum unter Verwendung von TMRA und des
  WDT ermittelt.

- Danach geht die Kontrolle an die PLL über. Es wird dabei
  jeweils nur ein Frequenzschritt gemacht.

Frage: Weiss jemand, ob die einzelnen RSel-Bereiche sich
überlappen? Und wenn ja, was sind die passenden DCOCTL-
Einstellungen?

zum langsamen Anschwingen des Quarzes: bei mir ist das Ding
jetzt stabil. Und Du willst doch auch "Low Power", oder?

sorry, daß noch keine vernünftige Dokumentation vorhanden ist.
Der Code kann sicherlich auch noch deutlich verbessert werden
hinsichtlich der Größe, für mich reichts aber erstmal.

Schreib kurz, wenn Du Fragen hast...

Achja.. ist für GCC.

bis dann, Jörg

von m@is (Gast)


Lesenswert?

ich habe auch ein Problem mit meinem 32kHz Quarz. Er schwingt mit
relativ kleiner Amplitudenänderung, aber korrekter Frequenz. Ich habe
ihn mit und ohne zusätzliche Kondensatoren angeschlossen (der MSP hat
ja schon intern 12pF).
Ich arbeite mit dem MSP430F1232, nutze den DCO bei max. Frequenz für
MCLK und möchte den 32kHz für ACLK und zum synchronosieren nutzen.

Den Schnippsel habe ich aus einem TI Beispiel.

BCSCTL1 &= ~OSCOFF;

  do {
      IFG1 &= ~OFIFG;
      for (w = 0xff; w>0; w--);
      }
  while ((IFG1 & OFIFG) != 0);


  BCSCTL2 = 0x88;

Leider komme ich nicht weiter, MSP verlässt die Schleife nicht.

Gruß m@is

von Jörg Zastrau (Gast)


Lesenswert?

Hi,

> Ich arbeite mit dem MSP430F1232, nutze den DCO bei max.
> Frequenz für MCLK und möchte den 32kHz für ACLK und
> zum synchronosieren nutzen.

> Den Schnippsel habe ich aus einem TI Beispiel.

> BCSCTL1 &= ~OSCOFF;

meiner Meinung nach ist OSCOFF-Flag im Status Register
und dient zur Einstellung des Low-Power modes (LPM4).
An der Stelle im BCSCTL1 steht das höherwertige Bit des
ACLK-Vorteilers (DIVA1), den Du hiermit löscht und den Teiler
damit in Abhängigkeit von DIVA0 auf /1 oder /2 einstellst.

>  do {
>      IFG1 &= ~OFIFG;
>      for (w = 0xff; w>0; w--);
>      }
>  while ((IFG1 & OFIFG) != 0);

bin ich auch zunächst drauf reingefallen. Da Du den 32kHz-Quarz
verwendest wird der Oszillator im LFXT-Modus betrieben. Das
Oszillator-Fault-Interrupt-Flag wird in diesem Modus nicht gesetzt,
d.h. die CPU wartet sich einen Ast...


>  BCSCTL2 = 0x88;

Hiermit wird auf XT2 (nicht präsent) für MCLK und SMCLK umgeschaltet.
Die Zeile kannst Du rauswerfen, da diese Clocks defaultmäßig mit dem
internen DCO laufen.

Ich benutzt Timer A, um auf den LFXT-Quarz zu warten...

Meine defines sind:
#define DCO_FREQ  2457600
#define TAR_TICKS  (DCO_FREQ/64)   // with WDT: 38,4kHz/8192
#define DCO_SETTLE  20              // settle time for DCO
#define LFXT_RETRY  40000
#define WDTCTL_INIT  WDTPW|WDTCNTCL|WDTTMSEL|WDTIS1|WDTSSEL
#define BCSCTL1_INIT  XT2OFF|RSEL2|RSEL1|RSEL0

die Funktion die(xxx) blinkt xxx mal mit einer Leuchtdiode und
hält die CPU bei Fehlern an.

Momentan sieht mein Code so aus:

[..schnipp..]

u16 retry=LFXT_RETRY;                   // retry counter

// wait for LFXT1CLK using Timer A
TACTL = TASSEL0+MC1+TACLR;              // start timer A using ACLK,
                                        // clear Interrupt flag
WDTCTL = WDTPW|WDTCNTCL|WDTHOLD;        // clear and stop
                                        // watchdogbefore interval
                                        // change

do { retry--;                           // ACLK works if timer
                                        // starts counting; loop
                                        // ~10cycles
} while ((TAR<4096)&&retry);            // wait some clock cycles
                                        // or retry

if (!retry)                             // timer A not working
                                        // -> die with postcode 4;
        die(PNOXT);                     // blink LED 8-)

[...schnapp...]


und dann weiter um den DCO auf eine definierte Startfrequenz
zu stellen (laufende Synchronisation noch nicht fertig... aber
Du kannst den Code aus SLAA074 nehmen, wenn Du Timer A frei hast):

[...schnipp...]

// since we have now a stable ACLK change
// the WDT timer with 15,625ms period in
// interval mode and use timer A in continous
// mode to adjust DCO frequency.

DCOCTL = 0x00;
BCSCTL1 = BCSCTL1_INIT;                 // choose high frequency
                                        // range

retry = 8;
signed int adjust;
do {  retry--;
  if ((adjust=wdt_poll(DCO_SETTLE))<0)  // timer A too fast?
      BCSCTL1 -=1;                      // yes -> decrease RSEL
                                        // value
} while ((adjust<0)&&retry);            // until DCO frequency
                                        // too low

if (!retry)                             // R-Selection failed
        die(PNOPLL);

// successive approximation for DCOCTL
int i;
   for (i=15; i>=0;i--) {               // process DCOx and MODx
                                        // Bits
      adjust = wdt_poll(DCO_SETTLE>>1);
      DCOCTL |= (1<<i);                 // try setting a higher
                                        // frequency
      if (adjust<0) {                   // too fast?
           DCOCTL &= ~(1<<(i+1));       // undo last frequency change
      }
}

[...schnapp...]

was noch fehlt ist die Routine wdt_poll... diese hier
ist für GCC (aufpassen mit TABs):

[...schnipp...]

int
wdt_poll(u16 t_settle)
{

int adjust = 0;

NOP_WAIT(t_settle);                     // stabilize clock

// well well, gcc is too clever..
// force setting of TACTL(0x160) and WDTCTL(0x120) using
// registers in a timely manner
// force fast polling of WDT_Flag and capture of Timer A (0x170)

 asm    ("   mov   %[wdc],   &0x120   \n\t"\
         "   mov   %[tac],   &0x160   \n\t"\
         "   bic   #1,       &0x002   \n\t"\
         "   mov   %[tic],   %[adj]   \n\t"\
         "1: bit.b #1,       &0x002   \n\t"\
         "   jz    1b                 \n\t"\
         "   sub   &0x170,   %[adj]   \n\t"\
         : [adj] "=r" (adjust)\
         : [wdc] "i" (WDTCTL_INIT),
[tac]"r"(TACLR+TASSEL1+MC1+ID0),[tic] "i" (TAR_TICKS>>1));

return adjust;
}


[...schnapp...]

danach kann man Timer A wieder benutzen... WDT ist natürlich
auch verkonfiguriert. Den DCO sollte mann gelegentlich wieder
nachstellen... bin da aber noch dran. Achja, das "r" für [tac]
ist kein Fehler...

der Code oben funktioniert (im Gegensatz zu meinem vorherigen
Posting 8-)) und ist getestet auf MSP430F1232...

schreib mal, ob's geklappt hat oder wenn ich was vergessen haben
sollte...

73,

Jörg

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.