Forum: Mikrocontroller und Digitale Elektronik PIC18 sporadisches Problem während Sleep Mode


von No N. (pascee)


Lesenswert?

Hallo zusammen,

ich schlage mich nun schon seit mehreren Tagen mit einem Problem herum 
und bin nun an einem Punkt an dem ich keine weiteren Ideen habe.

Zum Hintergrund:
Verwendet wird: MPLabX und der xc8 compiler in Verbindung mit dem ICD4 
Debugger.
Ich nutze einen PIC18 Modell 46k42 und versetze den durch eine bestimmte 
Aktion in den Schlafmodus und hole ihn durch einen Pin-Interrupt wieder 
heraus.

Das funktioniert auch in 90% der Fälle immer zuverlässig.
Jedoch kommt es manchmal zu einem (für mich noch unerklärlichen) 
Zustand, an dem der Pegelwechsel am Pin eindeutig vorhanden ist, jedoch 
der µC in seinem Sleep nicht mehr drauf reagiert. Ich weiß nicht woran 
es liegt um ehrlich zu sein.

Wenn das Ereignis eintritt um den PIC in den Sleep Mode zu setzen führe 
ich folgende Funktion aus:
1
void EnterSleep(void){
2
    GREEN_LED = LOW;
3
    RED_LED   = LOW;               
4
    TMR0_StopTimer();
5
    ADS1120_SetToSleep(ADC_DMS);
6
    ADS1120_SetToSleep(ADC_RateOfTurnVbat);
7
    ENABLE_5V_SetLow();
8
9
    bufferWPU.WPUA = WPUA;
10
    bufferWPU.WPUB = WPUB;
11
    bufferWPU.WPUC = WPUC;
12
    bufferWPU.WPUD = WPUD;   
13
    WPUA = 0;
14
    WPUB = 0;
15
    WPUC = 0;
16
    WPUD = 0;
17
    
18
    //
19
    CPUDOZEbits.IDLEN = 0;
20
    PIE3bits.U1TXIE = 0;
21
    PIR1bits.INT0IF = 0;
22
    VREGCONbits.VREGPM = 0; //Refering to P.176 -> normal power mode enabled 
23
                            // in sleep; draws higher current in sleep, faster wake up
24
    SLEEP();
25
}

Und wenn der Interrupt zum WakeUp kommt folgende Funktion:
1
void WakeUp(void)
2
{
3
  WPUA = bufferWPU.WPUA;
4
  WPUB = bufferWPU.WPUB;
5
  WPUC = bufferWPU.WPUC;
6
  WPUD = bufferWPU.WPUD;
7
  
8
  LED1_SetHigh();
9
  LED2_SetHigh();
10
  
11
  ENABLE_5V_SetHigh();
12
  __delay_ms(1);
13
  ADS1120_Init();
14
  ads1120_InitConfigurationRegister(ADC_DMS);
15
  ads1120_InitConfigurationRegister(ADC_RateOfTurnVbat); 
16
  LED1_SetLow();
17
  LED2_SetLow();
18
19
  if(ERR_5V_GetValue() == LOW)
20
  {
21
      int attempts = 0;
22
      bool state   = 0;
23
      while(attempts++ < 5 || !state)
24
      {
25
          __delay_us(1000);
26
          state = ERR_5V_GetValue();      
27
      }
28
      if(attempts >= 5 && state == LOW)
29
          Reset();
30
    
31
  }
32
  
33
  return;
34
}

Er geht auch nicht in einen Reset oder etwas dergleichen, weil ich den 
Neustart anhand der LED's erkennen würde.
Ich cleare auch extra das INT0IF bit um sicherzustellen, dass ich den 
nächsten Interrupt erkenne.


Ich wäre für jeden Tipp dankbar!

Schönen Sonntag noch

: Bearbeitet durch User
von H. B. (Gast)


Lesenswert?

Schaltplan

von hirth (Gast)


Lesenswert?

1
while (!Sleep()){
2
  sheep++;
3
}

von MosFeratu (Gast)


Lesenswert?

No N. schrieb:
> Ich wäre für jeden Tipp dankbar!

Erstmal, wie es auch die Netiquette empfiehlt, ein Programm mit den 
minimal nötigen Funktionen erstellen und ggf hier als Anhang 
reinstellen.

von Volker S. (vloki)


Lesenswert?

No N. schrieb:
> Zum Hintergrund:
> Verwendet wird: MPLabX und der xc8 compiler in Verbindung mit dem ICD4
> Debugger.
> Ich nutze einen PIC18 Modell 46k42 und versetze den durch eine bestimmte
> Aktion in den Schlafmodus und hole ihn durch einen Pin-Interrupt wieder
> heraus.

Wird der ICD im Debug Mode verwendet? Dann gibt es evtl. kein Sleep.

von pascee (Gast)


Lesenswert?

Guten Morgen,

Sorry, wird natürlich sofort nachgereicht.
main.c:
1
#include "mcc_generated_files/mcc.h"
2
#include "defines.h"
3
#include <string.h>
4
#include "functionsCenter.h"
5
#include "devicectrl.h"
6
#include "mcc_generated_files/tmr2.h"
7
#include  "ads1120.h"
8
9
10
void main(void)
11
{
12
    SYSTEM_Initialize();
13
    // Enable high priority global interrupts
14
    INTERRUPT_GlobalInterruptHighEnable();
15
    // Enable low priority global interrupts.
16
    INTERRUPT_GlobalInterruptLowEnable();
17
    
18
    LED1_SetLow();
19
    LED2_SetLow();  
20
   
21
#if defined(ADS1120_ON)
22
    ADS1120_Init();
23
    ADS1120_OffsetCalibration(ADC1);
24
    ADS1120_OffsetCalibration(ADC2);
25
    devicectrl_InitStructures();
26
    WWDT_SoftEnable(); 
27
    while (1)
28
    {
29
            WWDT_TimerClear();
30
        if(STARTUP_FINISHED)
31
                MY_StateMachine();        
32
        if(devctrl_SetToSleepMode)
33
          devicectrl_EnterPowerDownMode();    //Set PIC into power saving mode    
34
    }
35
}
36
37
void SYSTEM_Initialize(void)
38
{
39
    //INTERRUPT_Initialize
40
      INTCON0bits.IPEN = 1;
41
42
    // Assign peripheral interrupt priority vectors
43
    // UTXI - high priority
44
    IPR3bits.U1TXIP = 1;
45
    // URXI - high priority
46
    IPR3bits.U1RXIP = 1;
47
    // TMRI - high priority
48
    IPR3bits.TMR0IP = 1;
49
    // IOCI - low priority
50
    IPR0bits.IOCIP = 0;    
51
    // URXI - low priority
52
    IPR6bits.U2RXIP = 0;    
53
    // UTXI - low priority
54
    IPR6bits.U2TXIP = 0;   
55
    //
56
  
57
    //PMD_Initialize
58
      // CLKRMD CLKR enabled; SYSCMD SYSCLK enabled; SCANMD SCANNER enabled; FVRMD FVR enabled; IOCMD IOC enabled; CRCMD CRC enabled; HLVDMD HLVD enabled; NVMMD NVM enabled; 
59
    PMD0 = 0x00;
60
    // NCO1MD DDS(NCO1) enabled; TMR0MD TMR0 enabled; TMR1MD TMR1 enabled; TMR4MD TMR4 enabled; TMR5MD TMR5 enabled; TMR2MD TMR2 enabled; TMR3MD TMR3 enabled; TMR6MD TMR6 enabled; 
61
    PMD1 = 0x00;
62
    // ZCDMD ZCD enabled; DACMD DAC enabled; CMP1MD CMP1 enabled; ADCMD ADC enabled; CMP2MD CMP2 enabled; 
63
    PMD2 = 0x00;
64
    // CCP2MD CCP2 enabled; CCP1MD CCP1 enabled; CCP4MD CCP4 enabled; CCP3MD CCP3 enabled; PWM6MD PWM6 enabled; PWM5MD PWM5 enabled; PWM8MD PWM8 enabled; PWM7MD PWM7 enabled; 
65
    PMD3 = 0x00;
66
    // CWG3MD CWG3 enabled; CWG2MD CWG2 enabled; CWG1MD CWG1 enabled; 
67
    PMD4 = 0x00;
68
    // U2MD UART2 enabled; U1MD UART1 enabled; SPI1MD SPI1 enabled; I2C2MD I2C2 enabled; I2C1MD I2C1 enabled; 
69
    PMD5 = 0x00;
70
    // DSMMD DSM1 enabled; CLC3MD CLC3 enabled; CLC4MD CLC4 enabled; SMT1MD SMT1 enabled; CLC1MD CLC1 enabled; CLC2MD CLC2 enabled; 
71
    PMD6 = 0x00;
72
    // DMA1MD DMA1 enabled; DMA2MD DMA2 enabled; 
73
    PMD7 = 0x00;
74
  //
75
  
76
    //PIN_MANAGER_Initialize
77
/**
78
    LATx registers
79
    */
80
    LATE = 0x00;
81
    LATD = 0x30;
82
    LATA = 0xF8;
83
    LATB = 0x12;
84
    LATC = 0x08;
85
86
    /**
87
    TRISx registers
88
    */
89
    TRISE = 0x07;
90
    TRISA = 0x86;
91
    TRISB = 0xF5;
92
    TRISC = 0xB1;
93
    TRISD = 0x88;
94
95
    /**
96
    ANSELx registers
97
    */
98
    ANSELD = 0x08;
99
    ANSELC = 0x90;
100
    ANSELB = 0xE1;
101
    ANSELE = 0x07;
102
    ANSELA = 0x02;
103
104
    /**
105
    WPUx registers
106
    */
107
    WPUD = 0x00;
108
    WPUE = 0x00;
109
    WPUB = 0x10;
110
    WPUA = 0x80;
111
    WPUC = 0x08;
112
113
    /**
114
    RxyI2C registers
115
    */
116
    RB1I2C = 0x00;
117
    RB2I2C = 0x00;
118
    RC3I2C = 0x00;
119
    RC4I2C = 0x00;
120
    RD0I2C = 0x00;
121
    RD1I2C = 0x00;
122
    /**
123
    ODx registers
124
    */
125
    ODCONE = 0x00;
126
    ODCONA = 0x00;
127
    ODCONB = 0x00;
128
    ODCONC = 0x00;
129
    ODCOND = 0x00;
130
    /**
131
    SLRCONx registers
132
    */
133
    SLRCONA = 0xFF;
134
    SLRCONB = 0xFF;
135
    SLRCONC = 0xFF;
136
    SLRCOND = 0xFF;
137
    SLRCONE = 0x07;
138
    /**
139
    INLVLx registers
140
    */
141
    INLVLA = 0xFF;
142
    INLVLB = 0xFF;
143
    INLVLC = 0xFF;
144
    INLVLD = 0xFF;
145
    INLVLE = 0x0F;
146
    /**
147
    IOCx registers 
148
    */
149
    //interrupt on change for group IOCAF - flag
150
    IOCAFbits.IOCAF2 = 0;
151
    //interrupt on change for group IOCAF - flag
152
    IOCAFbits.IOCAF7 = 0;
153
    //interrupt on change for group IOCAN - negative
154
    IOCANbits.IOCAN2 = 1;
155
    //interrupt on change for group IOCAN - negative
156
    IOCANbits.IOCAN7 = 1;
157
    //interrupt on change for group IOCAP - positive
158
    IOCAPbits.IOCAP2 = 1;
159
    //interrupt on change for group IOCAP - positive
160
    IOCAPbits.IOCAP7 = 0;
161
    //interrupt on change for group IOCBF - flag
162
    IOCBFbits.IOCBF4 = 0;
163
    //interrupt on change for group IOCBN - negative
164
    IOCBNbits.IOCBN4 = 1;
165
    //interrupt on change for group IOCBP - positive
166
    IOCBPbits.IOCBP4 = 0;
167
    // register default IOC callback functions at runtime; use these methods to register a custom function
168
    IOCAF2_SetInterruptHandler(IOCAF2_DefaultInterruptHandler);
169
    IOCAF7_SetInterruptHandler(IOCAF7_DefaultInterruptHandler);
170
    IOCBF4_SetInterruptHandler(IOCBF4_DefaultInterruptHandler);      
171
   // Enable IOCI interrupt 
172
    PIE0bits.IOCIE = 1;   
173
    U2RXPPS = 0x1F;   //RD7->UART2:RX2;    
174
    SPI1SCKPPS = 0x09;   //RB1->SPI1:SCK1;    
175
    RB1PPS = 0x1E;   //RB1->SPI1:SCK1;    
176
    RC1PPS = 0x13;   //RC1->UART1:TX1;    
177
    RB3PPS = 0x1F;   //RB3->SPI1:SDO1;    
178
    RC6PPS = 0x15;   //RC6->UART1:RTS1;    
179
    U1RXPPS = 0x10;   //RC0->UART1:RX1;    
180
    RD6PPS = 0x16;   //RD6->UART2:TX2;    
181
    SPI1SDIPPS = 0x0A;   //RB2->SPI1:SDI1;    
182
    U1CTSPPS = 0x15;   //RC5->UART1:CTS1;      
183
  //
184
185
    //WWDT_Initialize();
186
  WDTCON0 = 18;
187
    WDTCON1 = 7|48;
188
  //  
189
    OSCILLATOR_Initialize();
190
    TMR2_Initialize();  
191
    TMR0_Initialize();  
192
    SPI1_Initialize();
193
}

Und hier die Interrupt routine aus dem pin_manager.c
1
void IOCAF2_DefaultInterruptHandler(void){
2
        if(STARTUP_FINISHED)
3
    {
4
        if(Conn_GetValue() == LOW)
5
        {        
6
            devctrl_SetToSleepMode = true;         
7
        }
8
        else if(Conn_GetValue() == HIGH)
9
        {          
10
                WakeUp(); //siehe erster Beitrag
11
                devctrl_SetToSleepMode = false;
12
          
13
            }
14
              ADS1120_StartConversion(ADC1);
15
              ADS1120_StartConversion(ADC2);
16
        }                   
17
    }
18
    IOCBFbits.IOCBF4 = 0;
19
}


viele Grüße und einen guten Start in die neue Woche !

von Teo D. (teoderix)


Angehängte Dateien:

Lesenswert?

Nix für ungut aber..... ;)

von pascee (Gast)


Lesenswert?

Ahhhh :-D F**k sorry !!!!

Der µC wird im Release Modus betrieben, also ohne Debugger.
Der ICD4 kann auch mit dem Sleep Modus umgehen.


viele Grüße

pascee

von Peter D. (peda)


Lesenswert?

Bei den AVRs gibt es eine Fallgrube, kann gut sein, daß es beim PIC 
ähnlich ist:
Der Interrupt zum Aufwachen kann ja direkt vor dem Sleep erfolgen und 
sich selber disablen, dann schläft der AVR für immer.
Man muß also beim AVR erstmal die Interrupts disablen, dann den 
Aufwacher enablen und dann Interrupt enable + Sleep direkt 
hintereinander schreiben. Der AVR führt den nächsten Befehl nach 
Interrupt enable immer aus, d.h. so kann vor dem Sleep kein Interrupt 
dazwischen grätschen.

von pascee (Gast)


Lesenswert?

vielen Dank für den Tipp!
Um dir richtig folgen zu können:


Peter D. schrieb:
> Bei den AVRs gibt es eine Fallgrube, kann gut sein, daß es beim
> PIC
> ähnlich ist:
> Der Interrupt zum Aufwachen kann ja direkt vor dem Sleep erfolgen und
> sich selber disablen, dann schläft der AVR für immer.

Du meinst, dass wenn der Fall des Interrupts kurz vor dem Aufruf der 
Sleepfunktion eintritt, ich in diesem case lande weil ich das interrupt 
flag dadurch nicht zurücksetze richtig?

> Man muß also beim AVR erstmal die Interrupts disablen, dann den
> Aufwacher enablen und dann Interrupt enable + Sleep direkt
> hintereinander schreiben. Der AVR führt den nächsten Befehl nach
> Interrupt enable immer aus, d.h. so kann vor dem Sleep kein Interrupt
> dazwischen grätschen.

Ab hier kann ich dir nicht mehr ganz folgen :-)
Ab wann müsste ich die Interrupts disablen?

von herba (Gast)


Lesenswert?

Schon mal versuchsweise den Soft-Watchdog deaktiviert? So wie ich das in 
Erinnerung habe, weckt dieser den Pic auf.
Gruss herba

von pascee (Gast)


Lesenswert?

Hi,

Das mit der Instruktion nach dem SLEEP() Aufruf stimmt übrigens und gilt 
auch für die PIC-Family.

Den Watchdog Timer deaktiviere ich immer wenn ich in den Sleep Mode 
gehe.

Habe jetzt noch eine Art Standby timer eingebaut, welcher während dem 
Sleep mode durchläuft und alle 10 sek einen Tick auslöst. Bei jedem Tick 
setze ich den HWPin-Interrupt zurück und nach 10 Minuten gibt es 
Sicherheitshalber ein HW-Reset sofern 10 Minuten im Sleep mode vergehen. 
Im laufenden Modus bleiben diese Funktionen natürlich deaktiviert.

Ich habe das System nun über Nacht einem Dauerstresstest unterzogen und 
der Fehler ist kein einziges mal aufgetreten. Sprich: in 10 Stunden ca. 
8000 Versuche. Das sollte doch ein Indiz dafür sein, dass der Fehler 
jetzt behoben sein sollte oder? :-)


viele Grüße und ein schönes Wochenende,

von Peter D. (peda)


Lesenswert?

pascee schrieb:
> Habe jetzt noch eine Art Standby timer eingebaut, welcher während dem
> Sleep mode durchläuft und alle 10 sek einen Tick auslöst.

Sowas nennt man einen Würg-Around. Du hast also die Ursache nicht 
gefunden und verschleierst den Fehler nur mit einem Timeout. Ein 
laufender Timer bedeutet in der Regel ein höherer Stromverbrauch im 
Sleep. Auch kann ein 10s Schluckauf dem Benutzer durchaus auffallen.

Deine unklare Fehlerbeschreibung und die Schnipseltaktik nützt aber 
keinem, da durchzusehen. Du müßtest schon ein komplettes compilierbares 
Programm als Zip anhängen. Und vor allen erstmal den ganzen sonstigen 
Schrunz raushauen, der mit dem Sleep-Problem nichts zu tun hat. Fehler 
findet man besser, wenn man das Programm so weit wie möglich 
vereinfacht.

von pascee (Gast)


Lesenswert?

Peter D. schrieb:
> pascee schrieb:
>> Habe jetzt noch eine Art Standby timer eingebaut, welcher während dem
>> Sleep mode durchläuft und alle 10 sek einen Tick auslöst.
>
> Sowas nennt man einen Würg-Around. Du hast also die Ursache nicht
> gefunden und verschleierst den Fehler nur mit einem Timeout. Ein
> laufender Timer bedeutet in der Regel ein höherer Stromverbrauch im
> Sleep. Auch kann ein 10s Schluckauf dem Benutzer durchaus auffallen.

Sorry ! Habe mich falsch ausgedrückt. Das Zurücksetzen des Pin Interrupt 
Flags gleich nach der Sleep Instruction hat geholfen. Das hat auch der 
Stresstest bewiesen :-)
Der Fehler ist bis heute nicht mehr aufgetaucht.

Den Timer habe ich Sicherheitshalber implementiert, da dass Gerät an 
eine unerreichbare Stelle kommt und ich keine Möglichkeit habe, es so 
einfach neuzustarten.

viele Grüße

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.