Forum: Mikrocontroller und Digitale Elektronik ATtiny 861 - Verhalten der Ports im Power Down?


von Holger K. (zaldo)


Lesenswert?

Hallo Zusammen,

ich habe hier ein kleines Problem. Schon im letzten Jahr habe ich aus 
Corona Langeweile angefangen, fürs Bobbycar von meinem Sohn ein 
Blaulicht/Martinshorn auf Basis des Tiny 861 zu bauen. Die LEDs für die 
Blitzer werden mit PWM angesteuert, wofür ich einen Soft-PWM Schnipsel 
eingebaut habe:
1
ISR(TIMER0_COMPA_vect) {
2
  static uint8_t pwm_cnt=0;
3
  uint8_t tmp=0;
4
  uint8_t buffer=PWM_PORT;
5
6
  OCR0A += (uint16_t)T_PWM;
7
8
  if (pwm_setting[0] > pwm_cnt) tmp |= (1<<1);
9
  if (pwm_setting[1] > pwm_cnt) tmp |= (1<<2);
10
11
  buffer &= ~(1<<1);
12
  buffer &= ~(1<<2);
13
  buffer |= (tmp);
14
  
15
  PWM_PORT = (buffer);                         // PWMs aktualisieren
16
17
  
18
  if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
19
  pwm_cnt=0;
20
  else
21
  pwm_cnt++;
22
}

Das funktioniert soweit alles prima. Nun habe ich einen Schleifenzähler, 
der nach etwa einer Minute ohne irgendeinen Tastendruck alles 
ausschaltet, und den µC in den Tiefschlaf schickt:
1
if ( sleep_counter > sleep)
2
  {
3
    pwm_setting[0]=0;
4
    pwm_setting[1]=0;
5
    horn1_state=0;
6
    horn2_state=0;
7
    flash_state=0;
8
    horn_tone_counter=0;
9
    horn_duration_counter=0;
10
    seq_cnt=0;
11
    
12
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
13
    sleep_mode();
14
    sleep_counter = 0;
15
  }
16
  
17
  sleep_counter++;
18
}

Auch das funktioniert soweit. Ton wird abgeschaltet, µC geht verlässlich 
in den Power Down (an der Stromaufnahme nachzuvollziehen) und wird beim 
nächsten Tastendruck per PCINT wieder aufgeweckt.

Allerdings: Ganz ganz selten, wenn der µC in den Power Down geht, gehen 
die beiden Pins für die Blitzer auf 1, d.h. alle LEDs werden (über Ihren 
vorgeschalteten Mosfet) voll durchgesteuert. Zum Glück sind die 
Batterien der limitierende Faktor, denn wenn die Spannung durch die 
Belastung von 12 LEDs nicht zusammen brechen würde, wären die mir bei 
4,5V jetzt schon ein paar mal abgebrannt. Aber warum passiert das 
überhaupt? Die Ports bleiben doch im Power Down nicht geschaltet oder 
etwa doch?

Gruß
Holger

von c-hater (Gast)


Lesenswert?

Holger K. schrieb:

> Aber warum passiert das
> überhaupt? Die Ports bleiben doch im Power Down nicht geschaltet oder
> etwa doch?

Natürlich behalten im PowerDown alle Ports ihren letzten Zustand. 
PowerDown bedeutet nichts anderes als: alles wird "eingefroren" und zwar 
durch Anhalten des Taktes, der all den Kram letztlich steuert.

Wenn man etwas anderes will, muss man das explizit machen, und zwar 
bevor man in den PowerDown geht.

von Sebastian S. (amateur)


Lesenswert?

R42 ist zu klein, zu groß oder so.
Ziemlich viel Code und zu wenig Information.

von Mario M. (thelonging)


Lesenswert?

Holger K. schrieb:
> Aber warum passiert das
> überhaupt?

Weil Du vor dem sleep_mode() nicht die Blitzer-Pins zurücksetzt.

von Holger K. (zaldo)


Lesenswert?

c-hater schrieb:
> Natürlich behalten im PowerDown alle Ports ihren letzten Zustand.

Ok, das erklärt es dann.

> Wenn man etwas anderes will, muss man das explizit machen

Habe ich, flash_state und pwm_setting[x] auf null. Dann friert er die 
wahrscheinlich ein, wenn er gerade in der Timer ISR beim kurzen 
On-Zyklus des PWM ist, und just in dem Moment das Power Down greift. 
Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.

Danke erstmal für den Tip.
Gruß
Holger

von c-hater (Gast)


Lesenswert?

Holger K. schrieb:

> Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.

Falscher Ansatz.

Richtig:
a) du wartest für dem PowerDown auf eine "günstige" Situation, also dass 
die LEDs "gerede eben" ausgeschaltet wurden.

b) du stellst einen Zustand her, in dem die Abläufe der der Ansteuerung 
egal werden. Sprich du koppelst die LED temporär von der Timer-Hardware 
ab und stellst händisch den gewünschten Zustand des Pins her.
Das erfordert dann natürlich, dass beim Aufwachen wieder die 
ursprüngliche Situation hergestellt wird, also Ansteuerung per 
Timer-Hardware.

Ich würde eindeutig Variante b) empfehlen, auch wenn sie erstmal 
deutlich mehr Arbeit macht.

Wenn dein System komplexer wird, wirst du ganz sicher irgendwann 
verstehen, warum ich diese Empfehlung gebe...

von Holger K. (zaldo)


Lesenswert?

Ja aber a) müsste ich ja genau damit erreichen. Denn jetzt leuchtet mir 
ein: pwm_setting[x]=0 setzt zwar beide Pins zurück, aber natürlich erst 
beim nächten durchlauf der ISR. Ich muss also eigentlich nur warten, 
bis ein PWM Zyklus komplett durchlaufen ist.

von Mario M. (thelonging)


Lesenswert?

Oder einfach warten, bis die LEDs aus sind.
1
while (PWM_PORT & (1<<1) + (1<<2));

von Sebastian S. (amateur)


Lesenswert?

Du bist der Jenige, der genau weiß, was der Rechner gerade macht!
Entweder Du hast eine Automatik, die sagt: Ab in die Heia!
Also eine Unterbrechung (z.B. Zeiter), oder irgendein anderes Ereignis.
Der Rechner "stolpert" ja nicht durch irgendeinen Zufall ins Bettchen.
Also ganz einfach an der Stelle die Peripherie in einen sinnvollen 
Zustand bringen. Bei flüchtigen Zuständen: Diese speichern und beim 
Aufwachen berücksichtigen. Der Grübler (µP) löscht ja seinen Speicher 
nicht beim Sprung in ein Bett.
Der aktuelle Zustand ist vor allem dann wichtig, wenn Du via PWM an 
einer H-Brücke rumspielst, oder bei ähnlichen Spielchen. Schaltest Du 
eine LED an, so bleibt diese eingeschaltet und deine Energieersparnis 
ist futsch.

von Manfred (Gast)


Lesenswert?

Holger K. schrieb:
> pwm_setting[x]=0 setzt zwar beide Pins zurück, aber natürlich erst
> beim nächten durchlauf der ISR.

Wieso braucht man für eine blinkende LED einen Interrrupt?
Für was braucht man dazu PWM - werden mehrere gedimmt, um ein 
Rundumlicht zu imitieren?

c-hater schrieb:
>> Dann werde ich mal versuchen vor dem Power Down eine Sekunde zu warten.
> Falscher Ansatz.

Ich bin immer wieder beeindruckt, wie unselbstständig die Leute 
unterwegs sind. Ich habe eine Anwendung, wo ich einen µC in den Sleep 
schicke. Ich habe garnicht darüber nachgedacht, sondern meine Ports 
natürlich zuvor in einem definierten Zustand.

Sebastian S. schrieb:
> Der Rechner "stolpert" ja nicht durch irgendeinen Zufall ins Bettchen.
> Also ganz einfach an der Stelle die Peripherie in einen sinnvollen
> Zustand bringen.

Das war zu einfach.

von Holger K. (zaldo)


Lesenswert?

Zum einen verträgt die LED die volle Versorgungsspannung nicht (eingangs 
erwähnt), zum anderen soll die Helligkeit später einmal analog zur 
Umgebungshelligkeit gedimmt werden.

Und, ich habe darüber nachgedacht, wenn Du Dir den Codeschnipsel 
zumindest mal angeschaut hättest, hättest Du vermutlich gesehen
1
pwm_setting[0]=0;
2
pwm_setting[1]=0;
3
horn1_state=0;
4
horn2_state=0;
5
flash_state=0;
6
horn_tone_counter=0;
7
horn_duration_counter=0;
8
seq_cnt=0;

Ich setzte immer so zum Spaß einen haufen Variablen zurück.

von Holger K. (zaldo)


Lesenswert?

Mario M. schrieb:
> Oder einfach warten, bis die LEDs aus sind.while (PWM_PORT &
> (1<<1) + (1<<2));

Auch ein sehr guter Ansatz, werde ich zur Sicherheit mit einbauen. Danke

von c-hater (Gast)


Lesenswert?

Holger K. schrieb:

> Auch ein sehr guter Ansatz, werde ich zur Sicherheit mit einbauen. Danke

Nein, das ist Variante a). Führt je nach Anwendung früher oder später 
in's Verderben.

Sicherlich machbar für einfache Sachen, ganz sicher für nur eine LED. 
Aber wehe, es wird mal etwas komplizierter...

Dann ist die "race condition" praktisch eingebaut. Nur Idioten machen 
das so, um das mal ganz deutlich zu sagen.

von Holger K. (zaldo)


Lesenswert?

c-hater schrieb:

> Nein, das ist Variante a). Führt je nach Anwendung früher oder später
> in's Verderben.

Da haben wir aneinander vorbeigeredet. Mit "warten bis die LEDs 
ausgeschaltet wurden" meinte ich, der Routiene auch die Zeit dazu zu 
geben, die Anforderung sie auszuschalten auch auszuführen.

Das ganze ist so nur enstanden weil ich damals (ist ja schon über ein 
Jahr her) irgendwo gelesen habe, die Ports würden im Power Down mode OC 
gehen. Nachdem das Verhalten dann aber vereinzelt aufgetreten ist, habe 
ich vor dem Power Down explizit die LEDs ausgeschaltet. Also dachte ich 
zumindest. Ich hab schlichtweg nicht dran gedacht, dass die Variablen ja 
erst in der Timer ISR ausgelesen werden.

Die Lösung von Mario M dachte ich mir nur als zweite Sicherung. 
Grundsätzlich soll der Sleep Timer ja die LEDs (und Akkustik) 
ausschalten, wenn die Zeit abgelaufen ist.

von Manfred (Gast)


Lesenswert?

Holger K. schrieb:
> Zum einen verträgt die LED die volle Versorgungsspannung nicht (eingangs 
erwähnt),

Ach, mal wieder LEDs ohne Strombegrenzung direkt an der Batterie?

Holger K. schrieb:
> Ich setzte immer so zum Spaß einen haufen Variablen zurück.

Kann es sein, dass zufällig kurz vor sleep die ISR kommt und das Licht 
wieder an macht, weil sie nicht gesperrt wurde?

c-hater schrieb:
> Dann ist die "race condition" praktisch eingebaut. Nur Idioten machen
> das so, um das mal ganz deutlich zu sagen.

Du bist wieder so lieb, dass ich da nicht mithalten kann.

von Holger K. (zaldo)


Lesenswert?

Der Vorwiderstand ist Ron vom Mosfet plus Ri von der Batterie.

Es ist ein Kinderspielzeug. Kein Kursrechner für eine Atomrakete.

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.