Forum: Mikrocontroller und Digitale Elektronik MSP430G2553, USCIB deinitialisieren..


von Holm T. (Gast)


Lesenswert?

Moin,

Ich habe hier ein Projekt mit einem MSP430 und einem RFM12, bei dem der 
Prozessor nach einem Timeout dem RFM12 über einen PNP Transistor den 
Saft klaut und sich mit LPM3 schlafen legen soll.
Damit in der Zwischenzeit keine parasitären Ströme über die SPI zum 
RFM12 fließen, muß ich die USCIB an der der RFM12 liegt 
deinitialisieren, also
die entsprechenden Portpins (P1.5,P1.6 und P1.7) auf Ausgang mit Low 
Potential schalten (oder auf Eingang floatend).

Die Applikation funktioniert nach dem Aufwachen wieder, nur sind meine 
Variablen weg, weil der Prozessor offensichtlich einen Reset an dieser 
Stelle macht. Für die Initialisierung und die Reinitialisierung nach dem 
LPM3 verwende ich die selben Routinen (USCIAset() und USCIBset()).

Das ist die Funktion zur initialisierung der USCIB:


void USCIBset() // Restore IO after LPM3
                // Setup the USCIB to RF12 Communication
{
    __disable_interrupt();
    P1SEL |=  BIT5 | BIT6 | BIT7;                       // P1.5 UCB0CLK, 
P1.6 UCB0SOMI, P1.7 UCB0SIMO
    P1SEL2 |= BIT5 | BIT6 | BIT7;                       // P1.5 UCB0CLK, 
P1.6 UCB0SOMI  P1.7 UCB0SIMO
    P1DIR |= BIT4; P1SEL &= ~BIT4;                      // P1.4 Output 
RFM12 Enable
    P1SEL2 &= ~BIT4; P1OUT |=BIT4;                      // P1.4 High 
RFM12 inactive

// USCI Channel B, 2 Wire SPI

    UCB0CTL1 |= UCSWRST;                        // Reset USCI B

   /*
    * Control Register 0
    *
    * ~UCCKPH -- Data is changed on the first UCLK edge and captured on 
the following edge
    * UCCKPL -- Inactive state is high
    * UCMSB -- MSB first
    * ~UC7BIT -- 8-bit
    * UCMST -- Master mode
    * UCMODE_0 -- 3-Pin SPI
    * UCSYNC -- Synchronous Mode
    *
    */

    UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCMODE_0 | UCSYNC; //mode(0,0)


   /*
    * Control Register 1
    *
    * UCSSEL_2 -- SMCLK
    * UCSWRST -- Enabled. USCI logic held in reset state
    */

    UCB0CTL1 = UCSSEL_2 | UCSWRST;      // SMCLK

    /* Bit Rate Control Register 0 */
    UCB0BR0 = 16;                       // SMCLK/16 = 921600hz
    //UCB0BR0 = 1;                      // SMCLK/1 = 1MHz

    /* Enable USCI */
    UCB0CTL1 &= ~UCSWRST;
    __enable_interrupt();

}

und hier die zur "Deinitialisierung"
void USCIBunset()   // To be called before LPM3 to lower current 
consumtion
                    // Reset USCIB to make the Processor signals input 
to
                    // prevent the RF12 to draw current
{
    __disable_interrupt();
                                            // P1.5 |P1.6 |P1.7 |P1.4
                                        //UCB0CLK|UCB0SOMI|UCB0SIMO|RF12SEL
    UCB0CTL1 = UCSWRST;                     // Reset USCI B
  P1OUT &= ~(BIT7|BIT6|BIT5|BIT4);            // pull to low
    P1DIR &= ~(BIT7|BIT6|BIT5);                 // Inputs
    P1SEL &= ~(BIT7|BIT6|BIT5);                 // IO Function
    P1SEL2 &=~(BIT7|BIT6|BIT5);                 // IO Function

    __enable_interrupt();
}


An und für sich sollte das disablen der Interrupts nicht notwendig sein, 
weil ich an dieser Stelle schon Alles "den Schlaf" störende 
ausgeschaltet habe. Der einzige freigegebene Int ist einer an P1.3 der 
den Prozessor aufwachen läßt und weitere Ints von dem Ding werden schon 
in der ISR abgeschaltet.

P1.4 das oben mit angesteuert wird, ist des Select Signal für den RFM12, 
deswegen sollte das auch nach Abschalten der Betriebsspannung des RFM 
auf GND gezogen werden, sonst versorgt sich auch von da der RFM12.

Gerufen wird die Abschalterei von hier:
void beforesleep()
{
        GAUGEPOWER_OFF;
        USCIAunset();                       // deactivate RS232
        USCIBunset();                       // make P1.5..P1.7 high 
impedance
        LED_ERR_OFF;                        // switch off LEDs
        LED_RX_OFF;                     // switch off LEDs
        LED_TX_OFF;                     // switch off LEDs
        fiveminto=TIMEOUT;                  // reload timeout value
        TA0CTL = TACLR;                     // Reset Timer A0
        TACCTL0 &= ~CCIE;                   // TACCR0 Int disable
        P1IFG &=~BIT3;                      // P1.3 Reset Int FLG
        P1IE |=BIT3;                        // P1.3 Interrupt Enable
        P2IE &= ~BIT0;                      // P2.0 Interrupt disable 
(SCK)
        WDTCTL = WDTPW|WDTHOLD;             // stop watchdog
        IE1 &= ~WDTIE;                      // disarm WDT int
}

wobei ich mit der Reihenfolge auch schon experimentiert habe.

Wenn ich den RFM12 aus der Fassung ziehe und auf die Deinitialisierung 
verzichte, wacht der Prozessor wieder so auf, wie er sollte, USCIA macht 
nur eine RS232 zu Debug Zwecken und außer das ich "Glitches" auf der TxD 
Leitung offensichtlich nicht vermeiden kann, funktioniert das dort mit 
USCIAUnset problemlos. Interrupts benutzen beide USCIs nicht.

Der Vollständigkeit halber noch die zur RS232 gehörenden Routinen:

void USCIAset() // Initialize  USCI Channel A, async UART
{
   /*
    * Control Register 1
    */

    UCA0CTL0 = 0;                               // ASYNC, 8 Bit, No 
Parity, 1Stopbit, UART Mode


   /*
    * Control Register 1
    *
    * ~UCSSEL_1
    * UCSSEL_0  BRCLK = ACLK
    * ~UCRXEIE  Errornous Character disabled
    * ~UCBRKIE  Received BREAK Charakters do not set UCA0RXIFG
    * ~UCDORM   Not dormant. All received characters will set UCA0RXIFG
    * ~UCTXADDR Next received character is data
    * ~UCTXBRK  Next frame transmitted is not BREAK
    * UCSWRST   Enables. USCI logic held in RESET
    *
    * Note: ~<BIT> indicates that <BIT> has value zero
    */

    UCA0CTL1 = 0;
    UCA0CTL1 |= UCSWRST;                        // RESET
    UCA0CTL1 |= UCSSEL0;                        // USCI use ACLK 32768Hz
    UCA0BR0 = 3;                                // 9600
    UCA0BR1 = 0;                                //
    UCA0MCTL = (UCBRS0 | UCBRS1) & ~UCOS16;     // Modulation 3
    P1SEL |= RXD |TXD;                          // P1.1 RXD, P1.2 TXD
    P1SEL2 |= RXD | TXD;                        // P1.1 RXD, P1.2 TXD
    UCA0CTL1 &= ~UCSWRST;                       // Start USCI state 
machine
}
//---------------------------------------------------------------------- 
----
void USCIAunset()   // Reset USCIA before LPM3
{
                                                // from sending garbadge
// still a glitch.. fixable?

    UCA0CTL1 |= UCSWRST;                        // Reset UCSIA
    P1SEL &= ~(RXD|TXD);
    P1SEL2 &= ~(RXD|TXD);                       // Make Pins standard IO
    P1OUT |= TXD;
    P1DIR |= TXD;                               // set to high to 
prevent TXD
}


Hat Jemand eine Idee wer mit da in die Suppe spucken könnte?
Der MSP430 nimmt in Ruhe erwartungsgemäß 0,8µA an 3,6V auf 
(Lithiumzelle).

Gruß,

Holm

von Max G. (l0wside) Benutzerseite


Lesenswert?

Seltsam. Interessant wäre zu wissen, an welcher Stelle der Reset 
passiert. Grob ins Blaue spekuliert: vielleicht mag es der USCI ja 
nicht, wenn du die Ports zwischendrin auf GPIO schaltest.

Ich würde wie folgt vorgehen:
* In der Deaktivierungsroutine die P1SEL (was ist denn P1SEL2?) 
rauswerfen und nur die Richtung mit P1DIR umschalten. Ggf. noch über 
P1OUT den Pullup ausschalten.
* Wenn das nicht hilft, step-by-step schauen, ob wirklich ein Reset 
kommt und wenn ja, an welcher Stelle. Kann es ein Watchdog-Problem sein?
* Dritter Schritt: bei e2e.ti.com nachfragen. Jens-Michael Gross hat 
sicher eine Idee :-)

Max

von Holm T. (Gast)


Lesenswert?

Max G. schrieb:
> Seltsam. Interessant wäre zu wissen, an welcher Stelle der Reset
> passiert. Grob ins Blaue spekuliert: vielleicht mag es der USCI ja
> nicht, wenn du die Ports zwischendrin auf GPIO schaltest.

Hmm, mögen ist gut...ich setze das Teil ja simpel zurück.
und die besser ausgebaute Schwester USCIA verträgt das scheinbar 
problemlos.
>
> Ich würde wie folgt vorgehen:
> * In der Deaktivierungsroutine die P1SEL (was ist denn P1SEL2?)

"Function Select Registers PxSEL and PxSEL2" nach slau144j.pdf S 329
MSP430x2xx Family Users Guide...

msp430g2553.h:

#define P1SEL2_               0x0041    /* Port 1 Selection 2 */


> rauswerfen und nur die Richtung mit P1DIR umschalten. Ggf. noch über
> P1OUT den Pullup ausschalten.

Ich werde das mal probieren, dauert aber noch ein Bisschen.

> * Wenn das nicht hilft, step-by-step schauen, ob wirklich ein Reset
> kommt und wenn ja, an welcher Stelle.

Das geht wegen LPM3 eher nicht.

Ich merke es daran, dass greeting() gerufen wird, das Ding aber im case 
0 - Zweig aufwachen sollte, ohne das greeting().

int main(void)
{
    char  stVal[17];
    char * s;

    ioinit();
    aftersleep();
    greeting();
    PGMState=1;

    while(1)
    {
        switch(PGMState)
        {
        // 0: sleep, waiting for an button press
            case 0:
                    {
                        print("S0\r\n");
                        beforesleep();
                        LPM3;
                        if(PGMState==0)
                            PGMState=1;
                        break;
                    }
        // 1: init rf12, goto state 2
            case 1:
                    {
                        aftersleep();
                        rf12_init();
                        PGMState=2;


> Kann es ein Watchdog-Problem sein?
> * Dritter Schritt: bei e2e.ti.com nachfragen. Jens-Michael Gross hat
> sicher eine Idee :-)
>
> Max

Watchdog ist zu diesem Zeitpunkt abgeschaltet und läuft sonst mit 1,9ms 
Interrupt als Zeitgeber..

Gruß,

Holm

von Max G. (l0wside) Benutzerseite


Lesenswert?

Bist du sicher, dass der Reset direkt nach dem Aufwachen kommt? Oder 
passiert dazwischen noch was?

Steht in den Errata was dazu?

Ansonsten wie gesagt: e2e.ti.com ist für MSP430-Themen hilfreicher als 
das Forum hier. Sorry.

Max

von Holm T. (Gast)


Lesenswert?

Nein, natürlich nicht sicher.
Ich merke nur das, wenn ich die USCIB nicht zurücksetzte, dass dann kein 
Reset passiert.
das hier mit MSP430 nicht so dermaßen viel lost ist, weiß ich..

Gruß,

Holm

von erik (Gast)


Lesenswert?

LPM3 - wird da der RAM schlafen gelegt ?

von ./. (Gast)


Lesenswert?

Vielleicht erstmal schaun ob da wirklich ein Reset kommt:

- Spannungsteiler von + nach GND aus 2 gleichen Widerständen
  an den Portpin hängen.
- Bei einem echten Reset wird das Pin Tri-State.

Dann sollte da die 1/2 Betriebsspannung auf dem Oszi zu sehen sein.

von Holm T. (Gast)


Lesenswert?

Auflösung des Rätsels:

Die Sache funktioniert schon wie programmiert, der Reset wurde im 
Prinzip nur durch das Zuschalten der Betriebsspannung für den RFM12 und 
eine externe China-Digitalmeßuhr verursacht. Etwas mehr Abblocken der 
Betriebsspannung am MSP430 (10µ) hat den Effekt dann beseitigt. 
Eigentlich hatte ich gedacht der der relativ kurz a nder Testschaltung 
angelötete olle Lithium-Handyakku von Siemens niederohmig genug sei und 
hatte nur mit 680n geblockt.
Verstärkt wurde der Effekt noch durch eine Diode in Reihe zur 
Betriebsspannung, der ich einen Strommesser parallel geschaltet hatte, 
ich wollte ja wissen wieviel das Ding im Schlafmodus so zieht und auch 
eine Überlastung des Strommessers vermeiden (Uni 11e, bis runter zu 3µA 
Vollausschlag, FET-Voltmeter).
Im Endeffekt erwies sich die 1N4148 in Durchlassrichtung auch als zu 
hochohmig, die Meßuhr startete nicht mehr richtig ohne parallel 
geschalteten Strommesser mit minimal 100mA Bereich. Evtl. Probiere ich 
nochmal irgend eine Schottky.

Die Sache funktioniert nun schon ein paar Tage wie sie soll.

Gruß,

Holm

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.