MSP430 Low Power Mode wechseln?

Gast #5062297
Lesenswert?

msp430g2xxx.h definiert einige intrinsics zu den "low power modes":
1
#define LPM0_bits              (CPUOFF)
2
...
3
#define LPM4_bits              (SCG1+SCG0+OSCOFF+CPUOFF)
4
#define LPM0      __bis_SR_register(LPM0_bits)         /* Enter Low Power Mode 0 */
5
#define LPM0_EXIT __bic_SR_register_on_exit(LPM0_bits) /* Exit Low Power Mode 0 */
6
...
7
#define LPM4      __bis_SR_register(LPM4_bits)         /* Enter Low Power Mode 4 */
8
#define LPM4_EXIT __bic_SR_register_on_exit(LPM4_bits) /* Exit Low Power Mode 4 */

zum Aktivieren und Verlassen bei Rückkehr aus einer ISR.
Wie kann jedoch der Modus gewechselt werden, also z.B. von LPM4 zu 
LPM1 (am Ende des pin-change Interrupts)?

Reicht evtl. ein
1
__bic_SR_register_on_exit(SCG1+OSCOFF);
?
Gast #5062443
Lesenswert?

Ich dachte, die _on_exit builtins machen genau dies: das auf dem Stack 
gesicherte SR modifizieren.

https://gcc.gnu.org/onlinedocs/gcc/MSP430-Built-in-Functions.html
> This clears the indicated bits in the saved copy of the status register 
currently residing on the stack. This only works inside interrupt handlers and the 
changes to the status register will only take affect once the handler returns.

http://www.rowleydownload.co.uk/msp430/documentation/__bic_SR_register_on_exit.htm
> __bic_SR_register_on_exit clears the bits specified in mask in the saved status 
register of an interrupt function (i.e. it bitwise ands the complement of mask 
into the saved status register). This allows you to change the operating mode of 
the MSP430 on return from the interrupt service routine, such as changing the low 
power mode.
> __bic_SR_register_on_exit can only be used in interrupt functions—an error is 
reported if it is used outside an interrupt function.

Ich brauch's aber gar nicht mehr, da ich den Code aus dem Interrupt 
herausgeholt habe und daher die CPU aktiv brauche.
#5062688
Lesenswert?

more power schrieb:
> Zum wechseln brauchst du beides.
1
__bic_SR_register_on_exit(LPM4_bits);
2
__bis_SR_register_on_exit(LPM1_bits);
3
/*  ^ */

Maximum Security Prison 430 schrieb:
> Ich brauch's aber gar nicht mehr, da ich den Code aus dem Interrupt
> herausgeholt habe

Das wird empfohlen; auch, weil mit einem kürzeren Interrupt-Handler 
andere Interrupts schneller behandelt werden können.
Gast #5062690
Lesenswert?

Nicht in diesem Fall (LPM4->LPM1), es müssen doch nur die 
"überflüssigen" bits gelöscht werden um die entsprechende Hardware 
wieder zu aktivieren.
Genau das war ja die Ausgangsfrage, ob man "LPM4_EXIT" (bits löschen) 
gefolgt von "LPM1" (bits schreiben) vermeiden kann.

Probiert habe ich es aber nicht.

Anwendung ist das Aufwachen und anschließendes, timergesteuertes Pollen 
(Entprellen etc.) bei Tastendruck. Man könnte so bei Bedarf fast ohne 
CPU-Einsatz (im Interrupt läuft sie) durch den pin-change Interrupt den 
Timer aktivieren.
Gast #5062715
Lesenswert?

wenn ich das richtig verstanden habe, willst Du nicht nach dem Verlassen 
der ISR die CPU aufwecken, sondern in einem anderen Low-Power-Mode 
weiterschlafen lassen. Dann darfst Du nicht die .._on_exit() intrinsics 
verwenden, denn die wirken sich erst bei Verlassen der ISR aus. Ich 
würde da direkt in der ISR mit dem __bic_SR_register() Befehl arbeiten:

Auszug aus der Header-Datei:
1
#define LPM1_bits              (SCG0+CPUOFF)
2
#define LPM4_bits              (SCG1+SCG0+OSCOFF+CPUOFF)

also sollte
1
 
2
__bic_SR_register(SCG1+OSCOFF)

von LPM4 nach LPM1 umschalten.

-- ungetestet

--wv
Gast #5062763
Lesenswert?

Die ISR wird in jedem Fall verlassen und das SR wiederhergestellt. D.h. 
deine vorgeschlagene Manipulation auf das SR (= Active Mode in der ISR) 
ändert nicht viel und wird sofort wieder überschrieben...
Gast #5069435
Lesenswert?

Im Family Data sheet steht im Abschnitt 2.2.3.1 "Interrupt Acceptance" 
ganz klar, daß das SR zurückgesetzt wird; das heißt, CPUOFF=0, also 
Active Mode.

Du mußt für den neuen Modus das SR aus dem Active Mode heraus 
entsprechend neu setzen.
Beitrag #5070420 wurde von einem Moderator gelöscht.
Gast #5070514
Lesenswert?

@ Mikael:

Bist ein ganz schlauer, gell?
ad 1: Im Eröffnungs-Thread steht MSP430G2xxxx - also gibt's dazu einen 
Family Datasheet.

ad 2: Um von einem LPM-Zustand in einen anderen zu wechseln, muß die MCU 
zuerst in den AM gehen - was für ein Wunder, natürlich ist das eine ISR.



Ergänzung zum ursprünglichen Thema:
Willst Du in einer ISR den Zustand wechseln, dann könnte das z.B. so 
aussehen:


add   #4,SP                  // Korrigiere die Stackpointer-Position
                             // (also das, was auch bei "reti" 
geschieht)
bis   #SCG1+OSCOFF,SR        // Wieder in den gewünschten LPM
Gast #5070570
Lesenswert?

JW schrieb:
> also gibt's dazu einen
> Family Datasheet

Nö, entweder Family User Guide oder Baustein Datenblatt,
aber kein Family Datenblatt. ;-)

JW schrieb:
> Willst Du in einer ISR den Zustand wechseln

Was fürn Schwachsinn? Wenn du den MSP430 innerhalb der ISR Schlafen 
schickst, wer soll ihn wieder wecken?

Da du den FUG nicht liest oder verstehst, schreib ich dirs noch einmal 
auf:

Beim Eintritt in die ISR rettet der uC das SR auf dem Stack. Dann kannst 
du deinen Kram machen. Und mit dem RETI restauriert der uC das SR (mit 
dem Wert vom Stack).
-> Dein Gefummele innerhalbb der ISR ist für die (Speicher-)Tonne.

JW schrieb:
> Bist ein ganz schlauer, gell?

Wenns um uns Beiden beim Thema MSP geht: JA!
Gast #5070669
Lesenswert?

Maximum Security Prison 430 schrieb:
> Kinder, Zeit für den Mittagsschlaf!

Geht ja leider nicht, bei dem Blödsinn. Über Geschmack läßt sich 
streiten und trotzdem sollte man jedem seine Meinung gönnen. Aber bei 
dem Thema hier ...

JW schrieb:
> add   #4,SP                  // Korrigiere die Stackpointer-Position
>                              // (also das, was auch bei "reti"
> geschieht)
> bis   #SCG1+OSCOFF,SR        // Wieder in den gewünschten LPM

Puhhh, das wird ja immer besser :'(

Probier das mal aus und berichte über deine Ergebnisse. :-P
Gast #5077981
Lesenswert?

So, hatte gerade mal das launchpad in der Hand. Mit 
__bis_SR_register_on_exit läßt sich der LPM beliebig wechseln oder 
auch verlassen. Getestet habe ich das mit folgendem Programm
1
// launchpad V line, G2553
2

3
#include "io430.h"
4
#include <stdlib.h>
5

6

7
#define LED_RED     BIT0
8
#define LED_GREEN   BIT6
9

10

11
int main( void )
12
{ 
13
  // Stop watchdog timer to prevent time out reset
14
  WDTCTL = WDTPW + WDTHOLD;
15
  
16
  // clock source DCO, set to 1MHz
17
  BCSCTL1 = CALBC1_1MHZ;
18
  DCOCTL = CALDCO_1MHZ;
19
 
20
  // output for LED
21
  P1SEL |= LED_GREEN;
22
  P1DIR |= (LED_GREEN | LED_RED);
23
  
24
  // f(PWM) 1kHz
25
  TACCR0 = 1000;
26
  // PWM value
27
  TACCR1 = 100;
28
  // outmode 7 for TA0.1
29
  TACCTL1 = OUTMOD_7;
30
  // init timer
31
  TACTL = TASSEL1 | MC0 | TACLR;
32
 
33
  // WDT Timer
34
  WDTCTL = WDT_MDLY_8;
35

36
  // enable interrupts
37
  IE1 |= WDTIE;
38
  
39
  // sleep until intr
40
  __bis_SR_register (LPM0_bits | GIE);
41
      
42
  // never reached
43
  return 0;
44
}
45

46

47
//Watchdog Timer interrupt service routine
48
#pragma vector=WDT_VECTOR
49
__interrupt void WDT_ISR (void)
50
{
51
  static unsigned int cnt = 0;
52
  static int pwm_speed = 0;
53
  static unsigned int rand_cnt = 5;
54

55
  // ca. 100ms (<- 96ms)
56
  if (cnt++ >= 12)
57
  {
58
    cnt  = 0;
59
    //
60
    // do every 100ms
61
    pwm_speed++;
62
    if (pwm_speed >= 50)
63
      pwm_speed = -49;
64
    TACCR1 = abs (pwm_speed) * 20;    
65

66
    if (rand_cnt-- == 0) 
67
    {
68
      rand_cnt = rand () % 10;
69
      // LED invers
70
      if (P1OUT & LED_RED)
71
        P1OUT &= ~LED_RED;
72
      else
73
        P1OUT |= LED_RED;
74
    }
75
  }
76

77
  __bis_SR_register_on_exit (LPM1_bits | GIE);
78
  
79
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren