Forum: Mikrocontroller und Digitale Elektronik Interrupt weckt PIC nicht aus Idle auf


von Bert 4. (b42)


Lesenswert?

uC: PIC24FJ64GA202

Ich bin auf ein seltsames Problem gestoßen: Ich starte eine Berechnung 
der Cryptographic Engine und möchte im Idle-Modus warten bis diese 
fertig ist. Das scheint mir eine normale Vorgehensweise zu sein, 
schließlich gibt es dafür extra einen Interrupt. Dummerweise weckt 
dieser den uC nicht auf. Hier ein Stück Code:
1
CRYCONHbits.CTRSIZE = 0b1111111;
2
CRYCONHbits.KEYMOD = 0b00;
3
CRYCONHbits.KEYSRC = 0b0000;
4
CRYCONLbits.CRYON = 0b1;
5
CRYCONLbits.CRYSIDL = 0b0;
6
CRYCONLbits.ROLLIE = 0b0;
7
CRYCONLbits.DONEIE = 0b1; // Interrupt einschalten
8
CRYCONLbits.FREEIE = 0b0;
9
CRYCONLbits.OPMOD = 0b0000;
10
CRYCONLbits.CPHRSEL = 0b1;
11
CRYCONLbits.CPHRMOD = 0b000;
12
memcpy((void*)&CRYKEY0, (const void*)mykey, 16);
13
memset((void*)&CRYTXTA, 0, 16);
14
// Hier ist IFS3bits.CRYDNIF == 0
15
CRYCONLbits.CRYGO = 1; // Berechnung starten
16
__builtin_disi(0x3FFF);
17
while(CRYCONLbits.CRYGO) // Warte bis Berechnung fertig
18
   Idle();
19
__builtin_disi(0);
20
// Jetzt ist IFS3bits.CRYDNIF == 1 (wenn man bis hier kommt)

Wenn ich das laufen lasse, blockiert es in der Schleife. Ersetze ich die 
Schleife durch "while(CRYCONLbits.CRYGO);", also ein Busy-Wait, 
funktioniert es. Wenn ich einen anderen Interrupt feuern lasse (z.B. pin 
change notification mit einem Taster), dann wacht er ebenfalls auf und 
entkommt der Schleife.
Hat jemand eine Idee was das sein könnte?

von Kastanie (Gast)


Lesenswert?

ohne in das Datenblatt geschaut zu haben:
Nicht jede Aktion kann im IDLE-Modus laufen, wie z.B. eine A/D-Wandlung.
Steht im Datenblatt, dass die Cryptographic Engine auch unabhängig im 
IDLE-Modus läuft oder benötigt sie den Systemtakt?

von Bert 4. (b42)


Lesenswert?

Kastanie schrieb:
> Steht im Datenblatt, dass die Cryptographic Engine auch unabhängig im
> IDLE-Modus läuft oder benötigt sie den Systemtakt?

Systemtakt (i.S.v. Peripherietakt)  braucht sie schon, daher darf man 
auch nicht in den Sleep-Mode gehen. Aber sie braucht keinen CPU-Takt. 
Sonst wäre das CRYSIDL-Bit sinnlos. Das Datenblatt sagt:

"22.4.2 OPERATION DURING IDLE MODE
When the CRYSIDL bit (CRYCONL<13>) is ‘0’, the engine will continue any 
ongoing operations without interruption when the device enters Idle 
mode.
When CRYSIDL is ‘1’, the module behaves as in Sleep modes."

PS: Es tut nichts zur Sache und ich kenne mich mit dem ADC auch nicht 
besonders gut aus, aber das Datenblatt sagt zum ADC "Operation During 
CPU Sleep and Idle modes".

: Bearbeitet durch User
von Kastanie (Gast)


Lesenswert?

Ok, dann sollte es eigentlich tun.
Das aktuellste Errata hast du sicher schon durchgesehen?
Ansonsten würde ich im Microchip-Forum nachfragen, da gibts auch am WE 
support.

von Bert 4. (b42)


Lesenswert?

Kastanie schrieb:
> Das aktuellste Errata hast du sicher schon durchgesehen?
Ja, nichts zu gefunden.

> Ansonsten würde ich im Microchip-Forum nachfragen, da gibts auch am WE
> support.
Bin dabei, allerdings scheinen die am WE keine neuen Accounts 
freizuschalten.

von Heinz R. (Gast)


Lesenswert?

Ohne mich wirklich auszukennen, nur vom Gefühl her:

Zu warten bis die Berechnung fertig ist und dann erst idle zu gehen
 ist eigentlich genau das was Du nicht wolltest.

Meine Vermutung: Es wäre besser ohne Warteschleife sofort idle zu gehen.
Dann würde der Interrupt auch erst im Idle- Zustand kommen
 und hätte die Chance den Prozessor aufzuwecken.

von Volker S. (vloki)


Lesenswert?

Bert 4. schrieb:
> Bin dabei, allerdings scheinen die am WE keine neuen Accounts
> freizuschalten

Die Administration des MCHP Forums ist leider generell mies :-(

von Bert 4. (b42)


Lesenswert?

Heinz R. schrieb:
> Ohne mich wirklich auszukennen, nur vom Gefühl her:
>
> Zu warten bis die Berechnung fertig ist und dann erst idle zu gehen
>  ist eigentlich genau das was Du nicht wolltest.
Nein, aber das mache ich ja auch nicht.

> Meine Vermutung: Es wäre besser ohne Warteschleife sofort idle zu gehen.
> Dann würde der Interrupt auch erst im Idle- Zustand kommen
>  und hätte die Chance den Prozessor aufzuwecken.
Für dieses Minimalbeispiel könnte man das so machen. Der 
Crypto-Interrupt ist ein bisschen speziell dahingehend, dass er 
garantiert erst eine bestimmte Zeit nach dem Start der Operation 
triggert. (Irgendwo in den Datenblättern gibt es eine Tabelle wieviele 
Takte jede Crypto-Operation braucht.)

Später in einem richtigen Programm brauche ich schon die Schleife, 
schließlich gibt es da auch andere Interrupts. Außerdem muss ich 
Interrupts global abschalten, damit die Abfrage und das Idle atomar 
passieren. (Beim PIC24 ist es so, dass er aufwacht wenn ein Interrupt 
individuell aktiviert ist, auch wenn Interrupts global aus sind.)


Aber wie dem auch sei, ich habe auch "CRYGO = 1; Idle();" getestet und 
es hat genau das gleiche Problem.


Volker S. schrieb:
> Die Administration des MCHP Forums ist leider generell mies :-(
Das habe ich befürchtet und deshalb hier gepostet.

von neuer PIC Freund (Gast)


Lesenswert?

Reicht der periphere Interrupt alleine aus, um das Idle zu überwinden. 
Oder muss dazu wenigstens eine leere ISR gegeben sein? Wo ist dann der 
code?

Und nicht dass du die PRIO auf 0 gesetzt hast.

von Kastanie (Gast)


Lesenswert?

Heinz R. meint, du solltest es so testen:

CRYCONLbits.CRYGO = 1; // Berechnung starten
__builtin_disi(0x3FFF);
   Idle();
while(CRYCONLbits.CRYGO) // (macht vor Idle() evtl. den Ärger)
__builtin_disi(0);

von Bert 4. (b42)


Lesenswert?

neuer PIC Freund schrieb im Beitrag #5413026:
> Reicht der periphere Interrupt alleine aus, um das Idle zu überwinden.
> Oder muss dazu wenigstens eine leere ISR gegeben sein? Wo ist dann der
> code?
Der ISR existiert natürlich, tut aber nichts:
1
void __attribute__ (( interrupt, no_auto_psv )) _CRYPTOInterrupt(void)
2
{
3
}
Ich habe auch testhalber Code eingebaut. Er wird nie ausgeführt.

> Und nicht dass du die PRIO auf 0 gesetzt hast.
Die Priorität habe ich nicht angefasst, per Default ist sie 4 (wie bei 
allen Interrupts, insbesondere bei CN, was ja funktioniert).

Kastanie schrieb:
> Heinz R. meint, du solltest es so testen:
>
> CRYCONLbits.CRYGO = 1; // Berechnung starten
> __builtin_disi(0x3FFF);
>    Idle();
> while(CRYCONLbits.CRYGO) // (macht vor Idle() evtl. den Ärger)
> __builtin_disi(0);
Ändert nichts. Ist meiner Ansicht nach aber auch konzeptionell falsch 
(oder zumindest riskant). Wenn ein anderer Interrupt direkt nach CRYGO=1 
feuert, würde man danach Idle gehen, selbst wenn die Crypto-Sache in der 
Zwischenzeit fertig ist. Du bräuchtest ein if vor dem Idle und dann 
kannst du auch gleich die Schleife dort hin setzen. Deine Schleife 
ergibt wenig Sinn, wieso sollte man wiederholt Interrupts einschalten?

von neuer PIC Freund (Gast)


Lesenswert?

Interrupt-Flag in ISR löschen.

Habs mal mit dem Timer1 anstatt Crypto im Simulator probiert. -> 
funktioniert.

von Bert 4. (b42)


Lesenswert?

neuer PIC Freund schrieb im Beitrag #5413105:
> Interrupt-Flag in ISR löschen.
Du hast recht, das sollte ich natürlich machen. Problem ist nur der ISR 
wird gar nicht aufgerufen.

Edit: Zur Klarstellung, der ISR wird deshalb nicht aufgerufen, weil die 
CPU nicht aufwacht. Es hat nichts mit den __builtin_disis zu tun. Der 
folgende Code hängt auch:
1
void __attribute__ (( interrupt, no_auto_psv )) _CRYPTOInterrupt(void)
2
{
3
   IFS3bits.CRYDNIF = 0;
4
}
5
6
int main()
7
{
8
   CRYCONHbits.CTRSIZE = 0b1111111;
9
   CRYCONHbits.KEYMOD = 0b00;
10
   CRYCONHbits.KEYSRC = 0b0000;
11
   CRYCONLbits.CRYON = 0b1;
12
   CRYCONLbits.CRYSIDL = 0b0;
13
   CRYCONLbits.ROLLIE = 0b0;
14
   CRYCONLbits.DONEIE = 0b1; // Interrupt einschalten
15
   CRYCONLbits.FREEIE = 0b0;
16
   CRYCONLbits.OPMOD = 0b0000;
17
   CRYCONLbits.CPHRSEL = 0b1;
18
   CRYCONLbits.CPHRMOD = 0b000;
19
   memcpy((void*)&CRYKEY0, (const void*)mykey, 16);
20
   memset((void*)&CRYTXTA, 0, 16);
21
   CRYCONLbits.CRYGO = 1; // Berechnung starten
22
   while(CRYCONLbits.CRYGO) // Warte bis Berechnung fertig
23
      Idle();
24
   /* ... */
25
   return 0;
26
}

Das Problem scheint wirklich eine Eigenheit der Crypto Engine zu sein. 
Andere Interrupts wie Timer oder CN wecken die CPU zuverlässig auf.

: Bearbeitet durch User
von Kastanie (Gast)


Lesenswert?

Bert 4. schrieb:
> Kastanie schrieb:
>> Heinz R. meint, du solltest es so testen:
>>
>> CRYCONLbits.CRYGO = 1; // Berechnung starten
>> __builtin_disi(0x3FFF);
>>    Idle();
>> while(CRYCONLbits.CRYGO) // (macht vor Idle() evtl. den Ärger)
>> __builtin_disi(0);
> Ändert nichts. Ist meiner Ansicht nach aber auch konzeptionell falsch
> (oder zumindest riskant). Wenn ein anderer Interrupt direkt nach CRYGO=1
> feuert, würde man danach Idle gehen, selbst wenn die Crypto-Sache in der
> Zwischenzeit fertig ist. Du bräuchtest ein if vor dem Idle und dann
> kannst du auch gleich die Schleife dort hin setzen. Deine Schleife
> ergibt wenig Sinn, wieso sollte man wiederholt Interrupts einschalten?



Sorry, ich habe natürlich den Strichpunkt bzw. eine Klammer nach der 
WhileZeile vergessen und dann sollte evtl. vor dem Idle noch das 
Interruptflag gelöscht werden.

Die WhileZeile kann man natürlich auch komplett entfernen, wenn nur der 
CryptoInterrupt aktiv ist.
1
__builtin_disi(0x3FFF);
2
   ClearCryptoEngineInterruptFlag;    // (sinngemäß)
3
   CRYCONLbits.CRYGO = 1; // Berechnung starten
4
   Idle();
5
__builtin_disi(0);
6
//while(CRYCONLbits.CRYGO) {}; // (macht vor Idle() evtl. den Ärger)

von Bert 4. (b42)


Lesenswert?

Kastanie schrieb:
>
1
> __builtin_disi(0x3FFF);
2
>    IFS3bits.CRYDNIF = 0;
3
>    CRYCONLbits.CRYGO = 1; // Berechnung starten
4
>    Idle();
5
> __builtin_disi(0);
6
>

In diesem Fall sehe ich nicht wofür man die __builtin_disi()s noch 
bräuchte. Aber unabhängig davon wacht er bei diesem Code-Stück nie aus 
dem Idle auf, es sei denn andere Interrupts feuern.

von Kastanie (Gast)


Lesenswert?

Ach, das ist ja ein PIC24 mit einer einstellbaren "Nix-Interrupt"-Zeit. 
Ich war gedanklich ganz woanders.

Dann ist das
1
__builtin_disi(0x3FFF);
natürlich in diesem Kontext falsch, da der Interrupt ab dann disabled 
wird.
Und daraus kann natürlich nichts erwachen...

Dann sollte es natürlich so sein:
1
   CRYCONLbits.CRYGO = 1; // Berechnung starten
2
   ClearCryptoEngineInterruptFlag;    // (sinngemäß)
3
__builtin_disi(0);
4
   Idle();

Aber das hast su sicher auch schon durchgecheckt?

von Bert 4. (b42)


Lesenswert?

Kastanie schrieb:
>
1
>    CRYCONLbits.CRYGO = 1; // Berechnung starten
2
>    ClearCryptoEngineInterruptFlag;    // (sinngemäß)
3
> __builtin_disi(0);
4
>    Idle();
5
>

Das Flag erst nach dem Start zu löschen halte ich für keine gute Idee. 
In diesem Minimalbeispiel macht es natürlich nichts, aber generell 
sollte man nicht ohne Weiteres annehmen, dass diese beiden Anweisungen 
atomar ausgeführt werden.


Nur zur Erinnerung: Beim PIC24 wecken lokal aktivierte Interrupts (will 
heißen *IE=1, in diesem Fall DONEIE=1) die CPU auf, auch wenn Interrupts 
global disabled sind (z.B. via __builtin_disi(0x3fff)). Letzteres 
beeinflusst nur ob/wann ISR aufgerufen wird, nicht das Aufwecken an 
sich.


Aber wie gesagt, das sind alles Nebenkriegsschauplätze. Solange mein uC 
nichts anderes tut und keine anderen Interrupts enabled, sollte dieser 
winzige Codeschnipsel funktionieren, tut es aber nicht:
1
CRYCONLbits.CRYON = 0b1;
2
CRYCONLbits.CRYSIDL = 0b0;
3
CRYCONLbits.DONEIE = 0b1;
4
CRYCONLbits.CPHRSEL = 0b1;
5
CRYCONLbits.CRYGO = 1;
6
while(CRYCONLbits.CRYGO) Idle();

PS: Wo wir es vorhin noch vom schlecht administrierten Microchip-Forum 
hatten - Jetzt ist es ganz down mit einem 404er...

: Bearbeitet durch User
von Bert 4. (b42)


Lesenswert?

Ein vorsichtiger Bump für diesen Thread. Ich wäre froh, wenn noch jemand 
eine Idee hätte.

Im offiziellen Microchip-Forum, wo Fragen wie diese zweifellos 
hingehören, ist kein Durchkommen. Es hat drei Tage gedauert, bis meine 
Registrierung freigeschaltet wurde, aber Beiträge darf ich dort offenbar 
trotzdem keine schreiben.

von Volker S. (vloki)


Lesenswert?

Bert 4. schrieb:
> Beiträge darf ich dort offenbar
> trotzdem keine schreiben.

Schreiben müsstest du können, aber die ersten Beiträge müssen von einem 
Admin abgesegnet werden, bevor sie sichtbar werden.
Nach massiven Spamatacken vor einiger Zeit ist das Forum für Einsteiger 
praktisch leider unbrauchbar geworden :-(

von Peter D. (peda)


Lesenswert?

Bert 4. schrieb:
> (Beim PIC24 ist es so, dass er aufwacht wenn ein Interrupt
> individuell aktiviert ist, auch wenn Interrupts global aus sind.)

Na wenn Du das so sagst, dann wird es wohl auch so im Datenblatt stehen.
Ich kenne mich mit den PICs nicht aus.

Bei den 8051 oder AVRs ist das Aufwachen jedenfalls deutlich anders:
- Interrupts müssen global, als auch der Aufwachinterrupt enabled sein.
- Es muß ein Interrupthandler dafür existieren.
- Das Sleep darf nicht in einem Interrupthandler aufgerufen werden.

von Bert 4. (b42)


Lesenswert?

Peter D. schrieb:
> Bert 4. schrieb:
>> (Beim PIC24 ist es so, dass er aufwacht wenn ein Interrupt
>> individuell aktiviert ist, auch wenn Interrupts global aus sind.)
>
> Na wenn Du das so sagst, dann wird es wohl auch so im Datenblatt stehen.
> Ich kenne mich mit den PICs nicht aus.
>
> Bei den 8051 oder AVRs ist das Aufwachen jedenfalls deutlich anders:
> - Interrupts müssen global, als auch der Aufwachinterrupt enabled sein.
> - Es muß ein Interrupthandler dafür existieren.
> - Das Sleep darf nicht in einem Interrupthandler aufgerufen werden.
Erstmal vorweg die Bemerkung, dass das nur ein Nebenkriegsschauplatz 
ist. Wie oben geschrieben, ist das Hauptproblem, dass der Interrupt 
nicht triggert. Auch dann nicht, wenn ich die ganzen 
__builtin_disi-Aufrufe weglasse.


Nun zu deiner Anmerkung: Ich bin auch relativ neu mit dem PICs. Bei der 
Aussage habe ich mich auf 10.2 im Datenblatt bezogen: "The device will 
wake from Idle mode on any of these events: • Any interrupt that is 
individually enabled • Any device Reset • A WDT time-out" Und natürlich 
auf diverse - nicht zwingend verlässliche - Internet-Quellen.


Das Grundproblem ist, dass man eine Methode braucht, um Dinge wie 
"if(!Interrupt) Sleep();" atomar zu machen. Sonst könnte der Interrupt 
zwischen der Abfrage und dem Sleep-Befehl kommen. Diese Methode ist auf 
jedem uC anders.
Soweit ich weiß nutzt man beim AVR aus, dass der SEI-Befehl Interrupts 
erst nach der darauf folgenden Anweisung freigibt. Dadurch kannst du CLI 
machen, dann testen, ob ein Interrupt vorliegt und wenn nicht "SEI; 
SLEEP" aufrufen. Sollte in der Zwischenzeit ein Interrupt aufgelaufen 
sein, triggert dieser erst nach Ausführen der SLEEP-Anweisung und der 
AVR wacht auf. Quelle: 
https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html


Beim PIC - so verstehe ich das zumindest - macht man es so wie in meinem 
obigen Betrag geschrieben. Quelle: 
http://www.microchip.com/forums/m885430.aspx#885464 (Der Thread ist im 
PIC32-Board, der Beitrag bezieht sich jedoch auf andere PICs.) Wenn das 
falsch ist, wäre ich froh um Aufklärung.


Volker S. schrieb:
> Schreiben müsstest du können, aber die ersten Beiträge müssen von einem
> Admin abgesegnet werden, bevor sie sichtbar werden.
> Nach massiven Spamatacken vor einiger Zeit ist das Forum für Einsteiger
> praktisch leider unbrauchbar geworden :-(
Ja, so kommt es mir auch vor. Ich habe einen Thread eröffnet und bekam 
die Meldung, dass er aufs Freischalten warten würde, was aber seit Tagen 
nicht passiert. Außerdem sollte - so wird es zumindest irgendwo in den 
Untiefen der Hilfeseiten erwähnt - mein nicht-freigeschaltener Beitrag 
in meinem Profil für mich sichtbar sein, ist er aber nicht. Entsprechend 
habe ich keine Ahnung, ob es nur sehr lange dauert oder ob er ganz 
verschluckt wurde.

von Volker S. (vloki)


Angehängte Dateien:

Lesenswert?

Bert 4. schrieb:
> Ja, so kommt es mir auch vor. Ich habe einen Thread eröffnet und bekam
> die Meldung, dass er aufs Freischalten warten würde, was aber seit Tagen
> nicht passiert. Außerdem sollte - so wird es zumindest irgendwo in den
> Untiefen der Hilfeseiten erwähnt - mein nicht-freigeschaltener Beitrag
> in meinem Profil für mich sichtbar sein, ist er aber nicht. Entsprechend
> habe ich keine Ahnung, ob es nur sehr lange dauert oder ob er ganz
> verschluckt wurde.

Das sollte dann eigentlich so wie angehängt aussehen.
"Approval Pending"

Möglicherweise findest du in einem alternativen Forum Hilfe.
http://picforum.ric323.com/viewforum.php?f=66

Da ist zwar nichts los, aber Ric und Susan scheinen regelmäßig rein zu 
schauen und die haben auch Ahnung ;-)

: Bearbeitet durch User
von B. P. (skorpionx)


Lesenswert?


von Bert 4. (b42)


Lesenswert?

Volker S. schrieb:
> Das sollte dann eigentlich so wie angehängt aussehen.
> "Approval Pending"
Bei mir sieht das nach gar nichts aus, weil es keine Spur von dem 
Beitrag gibt. Weder in dem entsprechenden Unterforum noch in meinem 
Profil. Ich habe nach dem Absenden nur die Bestätigung gekriegt, dass 
jetzt ein Admin approven müsste, seither sehe ich keine Spur mehr davon. 
Ich hoffe der wurde nicht einfach verschluckt. Oder gibt es eine 
spezielle Seite mit meinen verfassten aber nicht freigeschalteten 
Beiträgen und ich bin nur zu dumm die zu finden?

B. P. schrieb:
> Vielleicht verwandt...
> Beitrag "Timer1 weckt nicht den PIC2LF1840 vom SLEEP()"
Ich glaube nicht, denn da ging es 1. um eine andere uC-Familie und 2. um 
ein spezielles Problem mit Taktquellen für einen Timer. Die Timer und 
deren Interrupts funktionieren bei mir aber problemlos. Es ist nur 
speziell der Crypto-Interrupt, der nicht kommt.

: Bearbeitet durch User
von Kastanie (Gast)


Lesenswert?

Bert 4. schrieb:
> Nun zu deiner Anmerkung: Ich bin auch relativ neu mit dem PICs. Bei der
> Aussage habe ich mich auf 10.2 im Datenblatt bezogen: "The device will
> wake from Idle mode on any of these events: • Any interrupt that is
> individually enabled • Any device Reset • A WDT time-out" Und natürlich
> auf diverse - nicht zwingend verlässliche - Internet-Quellen.

Ich würde nicht behaupten, dass das ein Nebenkriegsschauplatz ist.
Und o.a. Datenblatt-Auszug bedeutet mitnichten, dass die globale 
Interruptfunktion unerheblich für das Aufwecken durch einzelne 
Interrupts ist.
Dieser muss in jedem Fall für eine Auslösung aktiv sein und nur dann 
gilt der o.a. Absatz.
Das Interruptflag hingegen wird immer gesetzt.

von Bert 4. (b42)


Lesenswert?

Ok, ich glaube ich habe den Preis für die dümmste Frage gewonnen.


Der Interrupt hat zwei(!) Enable-Bits. Eines in der Konfiguration der 
Crypto-Engine (CRYCONL.DONEIE) und dann noch eines in den 
Interrupt-Konfigurations-Registern (IEC3.CRYDNIE). Letzteres wird im 
Kapitel zur CryptoEngine und im zugehörigen Family Reference Manual 
natürlich genau null-mal erwähnt.


Ich hätte darauf kommen können, weil z.B. auch der CN-Interrupt zwei 
Enable-Bits hat. Allerdings macht es dort mehr Sinn, denn das eine Bit 
aktiviert CN-Interrupts generell, während das zweite den speziellen Pin 
freigibt. Beim Crypto weiß ich nicht was sie sich dabei gedacht haben. 
Vielleicht wollten sie die Option haben, mehrere Crypto-Engines zu 
verbauen? Scheint mir nicht besonders sinnvoll.


Aber egal, es funktioniert jetzt. Danke an alle, die zu helfen versucht 
haben!

von Peter D. (peda)


Lesenswert?

Bert 4. schrieb:
> Nur zur Erinnerung: Beim PIC24 wecken lokal aktivierte Interrupts (will
> heißen *IE=1, in diesem Fall DONEIE=1) die CPU auf, auch wenn Interrupts
> global disabled sind (z.B. via __builtin_disi(0x3fff)). Letzteres
> beeinflusst nur ob/wann ISR aufgerufen wird, nicht das Aufwecken an
> sich.

Die Idee ist recht clever und erspart einem jedwede atomic Hacks.
Man kann in aller Ruhe sleep ausführen und irgendwann danach das global 
enable, ohne daß man race-conditions befürchten muß.
Man merkt, die Entwickler haben mitgedacht, chapeau.

von Bert 4. (b42)


Lesenswert?

@Peter: Ja, das hat mir auch gefallen. Der einzige Nachteil ist, dass es 
keine zentrale Stelle gibt, um dieses Aufwecken abzuschalten. Wollte man 
das tun, so müsste man alle individuellen Interrupt-Schalter ausmachen. 
(Kann aber auch sein, dass es einen solchen Schalter gibt und ich ihn 
nur nicht kenne.)

@Kastanie: Du musst beachten, dass "Interrupts global abschalten" beim 
PIC24 eine etwas spezielle Bedeutung hat. Man legt nicht wie beim AVR 
ein Bit um, sondern man setzt das Prioritäts-Level der CPU aufs Maximum 
(ich glaube 7). Die CPU kann in ihrer Ausführung nur von Interrupts 
unterbrochen werden, die ein höheres (oder gleich hohes?) Level haben. 
Da alle Interrupts per Default Level 4 sind, schaltet man sie so quasi 
ab. Das betrifft aber nur das Anspringen der ISR, nicht das Aufwecken.

von Peter D. (peda)


Lesenswert?

Bert 4. schrieb:
> Der einzige Nachteil ist, dass es
> keine zentrale Stelle gibt, um dieses Aufwecken abzuschalten.

Ich sehe das nicht als großen Nachteil an.
Schaltet man das Aufwachen ab, kommt man doch nur noch mit einem Reset 
wieder raus. Bei Batteriebetrieb hieße das, man muß das Batteriefach 
öffnen und die Batterie entnehmen. Ich glaub nicht, daß ein Kunde sowas 
gut finden würde.

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.