AVR: µC geht nicht in den Idle-Mode

Gast #3921850
Lesenswert?

Hy Leute,

Ich arbeite gerade mit dem ATMEGA32L und soll so energiesparend wie 
möglich programmieren. Dafür möchte ich alle _delay_ms(); durch eine 
eigene Routine ersetzen, welche den µC für diese Zeit in den Idle-Mode 
schickt.
Ich habe das Programm außerhalb meines Hauptprogramms zur Testung 
geschrieben.
Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht 
funktioniert hat, kommentierte ich diese aus und versuchte es mit einem 
externen Interrupt.
Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als 
Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s 
wieder aus.

Ich konnte in anderen Beiträgen, bzw. im GCC Tutorial keinen Unterschied 
zu meinem Programm entdecken...

Vielen Dank im Voraus!
Angehängte Dateien:
#3922127
Lesenswert?

ghost schrieb:
> Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht
> funktioniert hat,

Das geht auch nicht. Im Sleep ist der Takt abgeschaltet. Dann hat der 
Timer nichts zum zählen.

ghost schrieb:
> Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als
> Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s
> wieder aus.

Wo kommen denn die 5s her? Und wieso dasselbe Ergebnis? Dasselbe wie 
was?

mfg.
#3922191
Lesenswert?

Thomas Eckmann schrieb:
> ghost schrieb:
>> Da die Variante mit Timer1 und ISR(TIMER1_COMPA_vect); nicht
>> funktioniert hat,
>
> Das geht auch nicht. Im Sleep ist der Takt abgeschaltet.

Nein.

> ghost schrieb:
>> Doch leider komm ich auf das selbe Ergebnis, die LED (welche mir als
>> Kontrolle dient) schaltet sich ca. alle 5s ein und nach weiteren 5s
>> wieder aus.
>
> Wo kommen denn die 5s her?

Ich hätte 2,2 erwartet, wenn das Schlafen nicht funktioniert.

> Und wieso dasselbe Ergebnis? Dasselbe wie was?

Das selbe wie mit Timer?

ghost schrieb:
> #define EXT_INT0_PIN    PD3
> #define EXT_INT1_PIN    PD2

Das ist falsch. Laut Datenblatt ist PD2 INT0 und PD3 INT1.
#3923855
Lesenswert?

Ich weiß leider auch nicht warum es 5s sind... die Frequenz (soft- und 
hardwaretechnisch) stimmt.

Das mit INT0 und INT1 ist in diesem Fall egal, weil beide gleich 
beschaltet werden, aber danke.

Ja genau, ich erhalte mit externem Interrupt und Timer1 dasselbe 
Ergebnis => kein Idle-Mode, LED schaltet sich alle 5s ein und aus. Auch 
der Stromverbrauch sinkt nicht während der Messung nicht(nur der Strom 
der LED bei EIN/AUS).
Gast #3924029
Lesenswert?

Thomas P. schrieb:
> Auszug aus delay.h:
> "The maximal possible delay is 262.14 ms / F_CPU in MHz."

Wenn's danach nicht weitergeht hast du aber noch eine sehr, sehr alte 
Version davon installiert.

Die nächsten Sätze wären nämlich:


When the user request delay which exceed the maximum possible one, 
_delay_ms() provides a decreased resolution functionality. In this mode 
_delay_ms() will work with a resolution of 1/10 ms, providing delays up 
to 6.5535 seconds (independent from CPU frequency). The user will not be 
informed about decreased resolution.


Und die "decreased resolution" ist sicher noch besser als 
Selbst-Zusammenstöpseln von Einzel-Delays in einer Schleife.
#3924092
Lesenswert?

Ich weiß, dass es nachher noch weiter geht! Aber ich wollte die maximal 
erreichbare Genauigkeit, da ich mit dem Oszi alles kontrolliere.

Aber darum geht es ja jetzt nicht. Ich möchte wissen, ob jemand einen 
Tipp hat, warum mein µC nicht in den Idle-Mode geht bzw. was ich 
vergessen oder falsch gemacht habe!
#3924196
Lesenswert?

Thomas P. schrieb:
> Aber darum geht es ja jetzt nicht. Ich möchte wissen, ob jemand einen
> Tipp hat, warum mein µC nicht in den Idle-Mode geht bzw. was ich
> vergessen oder falsch gemacht habe!

Ich habe mir Mal erlaubt, dein Programm in der Timerversion laufen zu 
lassen.

Atmega644, 1MHz, Prescaler = 64
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdlib.h>
5
#include <avr/sleep.h>
6

7
#define EXT_INT0_REG    DDRD
8
#define EXT_INT1_REG    DDRD
9
#define EXT_INT0_PORT    PORTD
10
#define EXT_INT1_PORT    PORTD
11
#define EXT_INT0_PIN    PD3
12
#define EXT_INT1_PIN    PD2
13

14

15
int main(void)
16
{      
17
  DDRA = 0x00;
18
  DDRB = 0x00;
19
  DDRC = 0x00;
20
//  DDRD = 0x00;
21
  PORTA = 0x00;
22
  PORTB = 0x00;
23
  PORTC = 0x00;
24
//  PORTD = 0x00;
25
  
26
  ACSR |= (1<<ACD);
27
  
28
  EXT_INT0_REG &= ~(1<<EXT_INT0_PIN);    // activate external interruptports
29
  EXT_INT0_PORT |= (1<<EXT_INT0_PIN);
30
  
31
//  GICR |= (1<<INT0);
32
  
33
  TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12);  // Prescaler 64 
34
  TIMSK1 |= (1<<OCIE1A);
35
  OCR1A = 5*975;    // max.: 975 => jede Sekunde ein Interrupt
36
            //
37
            // => 975/10 = 97 => alle 100ms ein Interrupt
38

39
  while(1)
40
  {
41
    DDRD &= ~(1<<PD7);
42
    PORTD &= ~(1<<PD7);
43
    
44
    for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++)
45
    {
46
      _delay_ms(200);
47
    }
48
  
49
    set_sleep_mode(SLEEP_MODE_IDLE);
50
    sei();
51
    sleep_enable();
52
    TCNT1 = 0;
53
    sleep_cpu();
54
    sleep_mode();
55

56
    sleep_disable();    
57
    DDRD |= (1<<PD7);
58
    PORTD |= (1<<PD7);
59
    
60
    for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++)
61
    {
62
      _delay_ms(200);
63
    }
64
  }
65
}
66

67
ISR(TIMER1_COMPA_vect)
68
{
69
  ;
70
}

Der Sleepmode wird erreicht und es läuft mit dem erwarteten Timing.

TIMSK1 muss in TIMSK geändert werden. Dann muss das bei dir auch laufen.

mfg.
Angehängte Dateien:
#3924687
Lesenswert?

Peter Dannegger schrieb:
> Dann stimmt Dein F_CPU nicht.
> Im Code hast Du ja 10 * 0,2s stehen.

11 * 0,2 s.

Thomas P. schrieb:
> Die Delays habe ich, um den Strom besser messen zu können.

Ja, aber wenn da 5 statt 2,2 Sekunden rauskommen und die Taktrate 
korrekt für das Delay angegeben ist, sind das 2,8 Sekunden zuviel. Die 
müssen ja irgendwo herkommen.

Thomas P. schrieb:
> Ich weiß, dass es nachher noch weiter geht! Aber ich wollte die maximal
> erreichbare Genauigkeit, da ich mit dem Oszi alles kontrolliere.

Die verlierst du durch deine Schleife außenrum aber auch. Und wenn der 
Takt vom internen R/C-Oszillator stammen sollte, ist der außerdem noch 
deutlich ungenauer.
#3924703
Lesenswert?

Thomas P. schrieb:
> Ich dachte, sleep_mode() ist die Zusammenfassung von sleep_enable() und
> sleep_cpu()? Warum benötige ich hier beides?

Benötigst du nicht. Da habe ich einfach nur zuviel wieder 
"einkommentiert".

Ich hab das Ganze jetzt ein wenig zusammengestrichen:

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdlib.h>
5
#include <avr/sleep.h>
6

7
int main(void)
8
{        
9
  ACSR |= (1<<ACD);
10
  
11
  TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12);  // Prescaler 64 
12
  TIMSK1 |= (1<<OCIE1A);
13
  OCR1A = 5*975;    // max.: 975 => jede Sekunde ein Interrupt
14
            //
15
            // => 975/10 = 97 => alle 100ms ein Interrupt
16
  
17
  DDRD |= (1<<PD7);
18
  set_sleep_mode(SLEEP_MODE_IDLE);
19
  sleep_enable();
20
  sei();
21

22
  while(1)
23
  {
24
    PORTD &= ~(1<<PD7);
25
    
26
    //for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) _delay_ms(200);
27
    _delay_ms(2200);
28

29
    TCNT1 = 0;
30
    sleep_cpu();
31
 
32
    PORTD |= (1<<PD7);
33
    
34
//   for(uint8_t cnt_1 = 0; cnt_1 <=10; cnt_1++) _delay_ms(200);
35
   _delay_ms(2200);
36
  }
37
}
38

39
ISR(TIMER1_COMPA_vect)
40
{
41
}

Thomas P. schrieb:
> Ich kann leider trotzdem keine Änderung des Stromes messen... 17mA (ohne
> Status-LED), weniger bekomm ich nicht!

Sleep Idle ist nicht sehr effektiv.

Bei mir beträgt der Unterschied 1,3mA (84,4mA : 83,1mA).
Auf meinem Testboard ist aber noch einiges mehr drauf. Der 644P 
verbraucht ca. 10mA bei 5V. Also gut 10% Ersparnis im Sleep.

Bei 3V beträgt der Unterschied nur noch 0,4mA.

mfg.

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