Forum: Mikrocontroller und Digitale Elektronik MSP430F2013 geht nicht in den LPM


von Technick (Gast)


Lesenswert?

Hi,
ich habe ein kleines Programm für den MSP430F2013 geschrieben. Es soll 
in den LPM4 gehen und danach nur auf den SPI Interrupt reagieren. Wenn 
es so einen Interrupt bekommen hat fängt es eben an zu arbeiten und geht 
zurück in den LPM.
Laut Datenblatt sollte der µC ca. 2µA im LPM4 ziehen, er zieht bei 2,2V 
allerdings ca. 640µA. Habt ihr eine Idee was ich falsch gemacht haben 
könnte?
Die externe Beschaltung kann ich soweit als Fehlerquelle ausschließen 
würde ich sagen. Ich habe auch sämtliche Bauteile entfernt, die 
irgendeine Verbindung zu Masse, oder einem anderen Signal darstellen 
könnten... Ohne Veränderung.
Das Programm zieht den "hohen" Strom übrigens auch direkt nach dem 
anschalten(mit einem Amperemeter im µA Bereich gemessen), also auch 
bevor es überhaupt einmal eine SPI Nachricht bekommen hat.
Folgend einmal mein Code:
1
#include <msp430x20x3.h>
2
#include <msp430.h>
3
void spi_out(void);
4
volatile  unsigned int i = 0x0000;
5
volatile  unsigned int adwert = 0x0000;
6
volatile  unsigned int adlo = 0x00;
7
volatile  unsigned int adhi = 0x00;
8
volatile unsigned int senden = 0x00;
9
volatile unsigned int empfangen = 0x00;
10
11
void main(void)
12
{
13
  WDTCTL = WDTPW + WDTHOLD;     // Stop watchdog Timer
14
15
  BCSCTL1 = CALBC1_1MHZ;      // Master clk auf 1MHz setzen um Stromsparend zu arbeiten
16
  DCOCTL = CALDCO_1MHZ;     
17
 // BCSCTL3 = LFXT1S_2;           // Setze LFTX1 auf VLO = 12kHz 
18
 
19
  //#########################  I/O setup  ###################################
20
  P1DIR &= ~(BIT4);      // Input direction
21
  P1OUT &= ~(BIT4);      // Pulldown resistor
22
  P1REN |=  (BIT4);      // Pulldown enable
23
  
24
  //#########################  ADC setup  ###################################
25
26
  SD16CTL  =  SD16REFON + SD16VMIDON + SD16SSEL_1;              //Referenzspannung ein, Clock einstellen
27
  P1SEL |= BIT3;
28
  SD16INCTL0 =  SD16INCH_0;                        // Auswahl ADC0(Pin:1.0+1.1)
29
  SD16CCTL0  =  SD16UNI + SD16IE;               //Unipolar, Interrupt einschalten
30
  SD16AE  = SD16AE0;                     //schaltet digitale Schaltung für diesen Pin ein
31
 
32
  //#########################  SPI setup  ###################################
33
  
34
  USICTL0 = USIPE7 + USIPE6 + USIPE5 + USIOE + USIGE; // Port, SPI Slave
35
  USICTL1 =  USIIE;               // Counter interrupt, flag remains set
36
  USICNT = 8;                              // init-load counter
37
  USICNT &= ~USI16B;                         // 16-bit-transmission
38
  USICTL0 &= ~USISWRST;                     //release for operation
39
  USICKCTL |= USICKPL;                      //Clock polarität, inaktiv=high
40
 // __bis_SR_register(LPM1_bits + GIE);       // Enter low power mode & enable interrupt
41
    
42
     __bis_SR_register(LPM4_bits + GIE);
43
  
44
}
45
46
// ADC interrupt service routine
47
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
48
#pragma vector = SD16_VECTOR
49
__interrupt void SD16ISR(void)
50
#elif defined(__GNUC__)
51
void __attribute__ ((interrupt(SD16_VECTOR))) SD16ISR (void)
52
#else
53
#error Compiler not supported!
54
#endif
55
{
56
    SD16CCTL0 &= ~ SD16IFG;               // clear ADC Interrupt Flag
57
    SD16CCTL0 |= SD16SC;                  // AD Wandler starten
58
    while (!(SD16CCTL0 & SD16IFG));       // AD Wandlung fertig ?
59
    adwert=SD16MEM0;
60
    adlo = (adwert & 0x00FF);
61
    adhi = (adwert & 0xFF00);
62
       
63
}
64
65
// USI interrupt service routine
66
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
67
#pragma vector=USI_VECTOR
68
__interrupt void universal_serial_interface(void)
69
#elif defined(__GNUC__)
70
void __attribute__ ((interrupt(USI_VECTOR))) universal_serial_interface (void)
71
#else
72
#error Compiler not supported!
73
#endif
74
{
75
   USICTL0 |= USISWRST;
76
   empfangen = USISRL;        // <-- Lesezugriff USISR
77
   SD16CCTL0 |= SD16IFG;               // clear ADC Interrupt Flag
78
79
  if (empfangen == 0x19)              //Abfrage ADC High byte
80
  {
81
      for (i = 0; i < 0x3600; i++);      
82
    senden = (adhi >> 8);
83
  }
84
  else if (empfangen == 0x54)         // Abfrage ADC Low byte
85
  {
86
    senden = adlo;
87
  }
88
  else if (empfangen == 0x20)         // Abfrage IO Pins 3&4 normaly low
89
  {
90
  /*   if((P1IN & BIT3))                //Pin4
91
     {
92
       if (P1IN &(BIT4))              //Pin4 und 5
93
       {
94
         senden = 0x88;
95
       }
96
       else
97
       {
98
         senden = 0x08;
99
       }
100
     } 
101
############ if wieder hinter else setzen!!!
102
     else */
103
     if ((P1IN &(BIT4)))           //Pin5 
104
     {
105
         senden = 0x80;
106
     }
107
     else
108
     {
109
         senden = 0x11;                 //falls keiner high ist sende 11
110
     }
111
  }
112
  else
113
  {
114
     senden = 0xE7;                     //Fehlercode, nichts empfangen
115
  }
116
117
  USISRL = senden;           // <-- Schreibzugriff USISR
118
  USICNT = 8;              // enable
119
  USICTL0 &= ~USISWRST;
120
}

Mit freundlichem Gruß
Der Technick

von für eine Hand voll Fragen (Gast)


Lesenswert?

Warum löschst du in der USI ISR das AD IFG?

Wann wird die USI ISR aufgerufen? Beim empfangen, beim senden, bei 
beidem? Wie wird auf die verschiedenen Möglichkeiten reagiert?

von Michael (Gast)


Lesenswert?

Mir fallen da spontan zwei Dinge ein. Zum einen (meine ich) sollte am 
Ende der ISR folgendes stehen:
1
__bic_SR_register(LPM4_bits + GIE);
Zum Anderen ein Klassiker auf den ich schon mehr als einmal reingefallen 
bin ... Hast du beim Testen den Debugger abgezogen?

von Stefan (Gast)


Lesenswert?

Du schaltest die Referenzpannungsquelle und deren Pufferstufe ein::
SD16CTL  =  SD16REFON + SD16VMIDON + SD16SSEL_1;
Beide brauchen dauerhaft nicht gerade wenig Strom.

von Name (Gast)


Lesenswert?

Ich hab schon ein sehr ähnliches Problem mit MSP gehabt. Ich danke das 
Problem lag  irgendwie an  den Oszillator, der einwenig Zeit zum 
stabilisieren braucht- Füge mal ein Delay von  ein paar ms vor

__bic_SR_register(LPM4_bits + GIE);

ein.

von family user guide (Gast)


Lesenswert?

Michael schrieb:
> Zum einen (meine ich) sollte
> am Ende der ISR folgendes stehen:__bic_SR_register(LPM4_bits + GIE);

Nein, das ist nicht erforderlich. Der uC stellt den LPM wieder her. Du 
musst nur eingreifen, wenn du den LPM andern willst.

von family user guide (Gast)


Lesenswert?

Name schrieb:
> Ich hab schon ein sehr ähnliches Problem mit MSP gehabt. Ich danke
> das Problem lag  irgendwie an  den Oszillator, der einwenig Zeit zum
> stabilisieren braucht- Füge mal ein Delay von  ein paar ms vor
> __bic_SR_register(LPM4_bits + GIE);
>
> ein.

Da wird vorher bereits eine Menge Code ausgeführt. Der Osz läuft schon 
stabil.

von Holm T. (Gast)


Lesenswert?

Ich kenne das zwar nur von Experimenten mit G2553 und LPM3, aber nach 
dem Wundern über den hohen Stromverbrauch kam dann beim nochmaligen 
Lesen der Manuale die Erkenntnis das man auch Pullups an Eingangspins 
und Ausgangstreiber abschalten sollte, bzw. Ausgänge auf low 
programmieren.
Auf die Art und Weise hatte ich dann weniger als 0,8µA erreicht.

Gruß,

Holm

von Technick (Gast)


Lesenswert?

Wow, danke schon mal für die vielen konstruktiven Antworten!
Ich werde das alles gleich mal ausprobieren. Und dann weiter berichten.
Zu euren Fragen:

für eine Hand voll Fragen schrieb:
> Warum löschst du in der USI ISR das AD IFG?

Hast recht, wäre anders übersichtlicher gewesen, ist aber soweit ich das 
Sehe von der Anwendung her egal, da der ADC Interrupt eh nur in der USI 
ISR ausgelöst werden kann.
Werde das aber auch noch mal ändern und auf Funktion testen.


für eine Hand voll Fragen schrieb:
> Wann wird die USI ISR aufgerufen? Beim empfangen, beim senden, bei
> beidem? Wie wird auf die verschiedenen Möglichkeiten reagiert?

Das USI Interface läuft ja in der Slave Funktion, ich verstehe nicht wie 
bzw. warum der Interrupt beim senden durchgeführt werden sollte.
Laut dem was ich aus Datenblatt/User Guide herausgelesen habe, sollte 
der Interrupt beim fertigen Empfang von Daten ausgelöst werden.


Michael schrieb:
> Zum Anderen ein Klassiker auf den ich schon mehr als einmal reingefallen
> bin ... Hast du beim Testen den Debugger abgezogen?

Ja, ich hab die Tests sowohl mit Debugger, als auch ohne Debugger 
durchgeführt. Ergebnisse waren beide die selben.

von Technick (Gast)


Lesenswert?

Muhaha,
vielen lieben Dank und fettes Lob an Stefan!

Stefan schrieb:
> Du schaltest die Referenzpannungsquelle und deren Pufferstufe ein::
> SD16CTL  =  SD16REFON + SD16VMIDON + SD16SSEL_1;
> Beide brauchen dauerhaft nicht gerade wenig Strom.

Genau diese Zeile hats tatsächlich gemacht! abgeschaltet und schon bin 
ich auf 5,86 µA runter!
Ich hoffe jetzt nur, dass das abrufen der ADC Daten schnell genug geht, 
wenn ich den Krempel mit in die ISR verschiebe.

Btw. Ihr scheint ja nicht wenig Ahnung zu haben und das hier ist mein 
erstes wirkliches Programm... Wenn ihr Ideen habt, wie man das ganze 
"schöner" schreiben, bzw. optimieren kann bin ich auch für alle 
Ratschläge offen :)

Danke nochmal an alle beteiligten!

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.